summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--firmware/export/config-ondavx747.h6
-rw-r--r--firmware/export/jz4740-codec.h4
-rw-r--r--firmware/export/jz4740.h2
-rw-r--r--firmware/sound.c2
-rw-r--r--firmware/target/mips/ingenic_jz47xx/codec-jz4740.c93
-rw-r--r--firmware/target/mips/ingenic_jz47xx/pcm-jz4740.c115
-rw-r--r--firmware/target/mips/ingenic_jz47xx/system-target.h4
7 files changed, 114 insertions, 112 deletions
diff --git a/firmware/export/config-ondavx747.h b/firmware/export/config-ondavx747.h
index 176a35f4e9..b603e02c2b 100644
--- a/firmware/export/config-ondavx747.h
+++ b/firmware/export/config-ondavx747.h
@@ -122,6 +122,9 @@
122/* Define this if you have the Jz4740 internal codec */ 122/* Define this if you have the Jz4740 internal codec */
123#define HAVE_JZ4740_CODEC 123#define HAVE_JZ4740_CODEC
124 124
125/* has no tone controls, so we use the software ones */
126#define HAVE_SW_TONE_CONTROLS
127
125/* define the bitmask of hardware sample rates */ 128/* define the bitmask of hardware sample rates */
126#define HW_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32 | \ 129#define HW_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32 | \
127 SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16 | \ 130 SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16 | \
@@ -131,9 +134,6 @@
131 134
132#define NEED_ADC_CLOSE 1 135#define NEED_ADC_CLOSE 1
133 136
134/* has no tone controls, so we use the software ones */
135//#define HAVE_SW_TONE_CONTROLS
136
137#define BATTERY_CAPACITY_DEFAULT 1250 /* default battery capacity */ 137#define BATTERY_CAPACITY_DEFAULT 1250 /* default battery capacity */
138#define BATTERY_CAPACITY_MIN 500 /* min. capacity selectable */ 138#define BATTERY_CAPACITY_MIN 500 /* min. capacity selectable */
139#define BATTERY_CAPACITY_MAX 2500 /* max. capacity selectable */ 139#define BATTERY_CAPACITY_MAX 2500 /* max. capacity selectable */
diff --git a/firmware/export/jz4740-codec.h b/firmware/export/jz4740-codec.h
index e8751b5141..c98bfba602 100644
--- a/firmware/export/jz4740-codec.h
+++ b/firmware/export/jz4740-codec.h
@@ -21,11 +21,7 @@
21#ifndef __JZ4740_CODEC_H_ 21#ifndef __JZ4740_CODEC_H_
22#define __JZ4740_CODEC_H_ 22#define __JZ4740_CODEC_H_
23 23
24/* TODO */
25#define VOLUME_MIN -730 24#define VOLUME_MIN -730
26#define VOLUME_MAX 60 25#define VOLUME_MAX 60
27 26
28int tenthdb2master(int db);
29void audiohw_set_headphone_vol(int vol_l, int vol_r);
30
31#endif /* __JZ4740_CODEC_H_ */ 27#endif /* __JZ4740_CODEC_H_ */
diff --git a/firmware/export/jz4740.h b/firmware/export/jz4740.h
index 7ddec364a6..3bf34bd342 100644
--- a/firmware/export/jz4740.h
+++ b/firmware/export/jz4740.h
@@ -1310,8 +1310,6 @@
1310#define ICDC_CDCCR2_MICBG(n) ((n & 0x3) << 4) 1310#define ICDC_CDCCR2_MICBG(n) ((n & 0x3) << 4)
1311#define ICDC_CDCCR2_HPVOL(n) ((n & 0x3) << 0) 1311#define ICDC_CDCCR2_HPVOL(n) ((n & 0x3) << 0)
1312 1312
1313#define ICDC_CDCCR2_AINVOL_DB(n) ((n+34.5)/1.5)
1314
1315#define ICDC_CDCCR2_SMPR_8 (0) 1313#define ICDC_CDCCR2_SMPR_8 (0)
1316#define ICDC_CDCCR2_SMPR_11 (1) 1314#define ICDC_CDCCR2_SMPR_11 (1)
1317#define ICDC_CDCCR2_SMPR_12 (2) 1315#define ICDC_CDCCR2_SMPR_12 (2)
diff --git a/firmware/sound.c b/firmware/sound.c
index 0e16c5a3a9..bca98b039c 100644
--- a/firmware/sound.c
+++ b/firmware/sound.c
@@ -264,6 +264,8 @@ static void set_prescaled_volume(void)
264 264
265#elif defined(HAVE_TLV320) || defined(HAVE_WM8978) || defined(HAVE_WM8985) 265#elif defined(HAVE_TLV320) || defined(HAVE_WM8978) || defined(HAVE_WM8985)
266 audiohw_set_headphone_vol(tenthdb2master(l), tenthdb2master(r)); 266 audiohw_set_headphone_vol(tenthdb2master(l), tenthdb2master(r));
267#elif defined(HAVE_JZ4740_CODEC)
268 audiohw_set_volume(current_volume);
267#endif 269#endif
268} 270}
269#endif /* (CONFIG_CODEC == MAS3507D) || defined HAVE_UDA1380 */ 271#endif /* (CONFIG_CODEC == MAS3507D) || defined HAVE_UDA1380 */
diff --git a/firmware/target/mips/ingenic_jz47xx/codec-jz4740.c b/firmware/target/mips/ingenic_jz47xx/codec-jz4740.c
index 44d291f312..6a0b6ae340 100644
--- a/firmware/target/mips/ingenic_jz47xx/codec-jz4740.c
+++ b/firmware/target/mips/ingenic_jz47xx/codec-jz4740.c
@@ -26,7 +26,7 @@
26 26
27/* TODO */ 27/* TODO */
28const struct sound_settings_info audiohw_settings[] = { 28const struct sound_settings_info audiohw_settings[] = {
29 [SOUND_VOLUME] = {"dB", 0, 1, -73, 6, -20}, 29 [SOUND_VOLUME] = {"dB", 0, 2, 0, 6, 0},
30 /* HAVE_SW_TONE_CONTROLS */ 30 /* HAVE_SW_TONE_CONTROLS */
31 [SOUND_BASS] = {"dB", 0, 1, -24, 24, 0}, 31 [SOUND_BASS] = {"dB", 0, 1, -24, 24, 0},
32 [SOUND_TREBLE] = {"dB", 0, 1, -24, 24, 0}, 32 [SOUND_TREBLE] = {"dB", 0, 1, -24, 24, 0},
@@ -62,40 +62,39 @@ static void i2s_codec_init(void)
62{ 62{
63 __cpm_start_aic1(); 63 __cpm_start_aic1();
64 __cpm_start_aic2(); 64 __cpm_start_aic2();
65 65
66 __aic_enable(); 66 __aic_enable();
67 67
68 __i2s_internal_codec(); 68 __i2s_internal_codec();
69 __i2s_as_slave(); 69 __i2s_as_slave();
70 __i2s_select_i2s(); 70 __i2s_select_i2s();
71 __aic_select_i2s(); 71 __aic_select_i2s();
72 72
73 __aic_disable_byteswap(); 73 __aic_disable_byteswap();
74 __aic_disable_unsignadj(); 74 __aic_disable_unsignadj();
75 __aic_disable_mono2stereo(); 75 __aic_disable_mono2stereo();
76 76
77 i2s_codec_reset(); 77 i2s_codec_reset();
78 78
79 //REG_ICDC_CDCCR2 = (ICDC_CDCCR2_AINVOL(ICDC_CDCCR2_AINVOL_DB(0)) | ICDC_CDCCR2_SMPR(ICDC_CDCCR2_SMPR_48) 79 REG_ICDC_CDCCR1 &= ~(ICDC_CDCCR1_SUSPD | ICDC_CDCCR1_RST);
80
80 REG_ICDC_CDCCR2 = ( ICDC_CDCCR2_AINVOL(14) | ICDC_CDCCR2_SMPR(ICDC_CDCCR2_SMPR_44) 81 REG_ICDC_CDCCR2 = ( ICDC_CDCCR2_AINVOL(14) | ICDC_CDCCR2_SMPR(ICDC_CDCCR2_SMPR_44)
81 | ICDC_CDCCR2_HPVOL(ICDC_CDCCR2_HPVOL_0)); 82 | ICDC_CDCCR2_HPVOL(ICDC_CDCCR2_HPVOL_0));
82
83 REG_ICDC_CDCCR1 &= ~(ICDC_CDCCR1_SUSPD | ICDC_CDCCR1_RST);
84 83
85 mdelay(15); 84 mdelay(15);
86 REG_ICDC_CDCCR1 &= ~(ICDC_CDCCR1_PDVR | ICDC_CDCCR1_VRCGL | ICDC_CDCCR1_VRCGH); 85 REG_ICDC_CDCCR1 &= ~(ICDC_CDCCR1_PDVR | ICDC_CDCCR1_VRCGL | ICDC_CDCCR1_VRCGH);
87 REG_ICDC_CDCCR1 |= (ICDC_CDCCR1_EDAC | ICDC_CDCCR1_HPCG); 86 REG_ICDC_CDCCR1 |= (ICDC_CDCCR1_EDAC | ICDC_CDCCR1_HPCG);
88 87
89 mdelay(600); 88 mdelay(600);
90 REG_ICDC_CDCCR1 &= ~(ICDC_CDCCR1_PDVRA | ICDC_CDCCR1_HPCG | ICDC_CDCCR1_PDHPM | ICDC_CDCCR1_PDHP); 89 REG_ICDC_CDCCR1 &= ~(ICDC_CDCCR1_PDVRA | ICDC_CDCCR1_HPCG | ICDC_CDCCR1_PDHPM | ICDC_CDCCR1_PDHP);
91 90
92 mdelay(2); 91 mdelay(2);
93 92
94 /* CDCCR1.ELININ=0, CDCCR1.EMIC=0, CDCCR1.EADC=0, CDCCR1.SW1ON=0, CDCCR1.EDAC=1, CDCCR1.SW2ON=1, CDCCR1.HPMUTE=0 */ 93 /* CDCCR1.ELININ=0, CDCCR1.EMIC=0, CDCCR1.EADC=0, CDCCR1.SW1ON=0, CDCCR1.EDAC=1, CDCCR1.SW2ON=1, CDCCR1.HPMUTE=0 */
95 REG_ICDC_CDCCR1 = (REG_ICDC_CDCCR1 & ~(ICDC_CDCCR1_ELININ | ICDC_CDCCR1_EMIC | ICDC_CDCCR1_EADC | 94 REG_ICDC_CDCCR1 = (REG_ICDC_CDCCR1 & ~(ICDC_CDCCR1_ELININ | ICDC_CDCCR1_EMIC | ICDC_CDCCR1_EADC |
96 ICDC_CDCCR1_SW1ON | ICDC_CDCCR1_HPMUTE)) | (ICDC_CDCCR1_EDAC 95 ICDC_CDCCR1_SW1ON | ICDC_CDCCR1_HPMUTE)) | (ICDC_CDCCR1_EDAC
97 | ICDC_CDCCR1_SW2ON); 96 | ICDC_CDCCR1_SW2ON);
98 97
99 HP_on_off_flag = 1; /* HP is on */ 98 HP_on_off_flag = 1; /* HP is on */
100} 99}
101 100
@@ -111,7 +110,7 @@ static void i2s_codec_set_mic(unsigned short v) /* 0 <= v <= 100 */
111 REG_ICDC_CDCCR2 = ((REG_ICDC_CDCCR2 & ~(0x1f << 16)) | (codec_mic_gain << 16)); 110 REG_ICDC_CDCCR2 = ((REG_ICDC_CDCCR2 & ~(0x1f << 16)) | (codec_mic_gain << 16));
112} 111}
113 112
114static void i2s_codec_set_bass(unsigned short v) /* 0 <= v <= 100 */ 113static void i2s_codec_set_base(unsigned short v) /* 0 <= v <= 100 */
115{ 114{
116 v &= 0xff; 115 v &= 0xff;
117 116
@@ -200,6 +199,7 @@ static unsigned short i2s_codec_get_volume(void)
200 return val; 199 return val;
201} 200}
202 201
202static unsigned long HP_register_value;
203static void HP_turn_on(void) 203static void HP_turn_on(void)
204{ 204{
205 //see 1.3.4.1 205 //see 1.3.4.1
@@ -261,11 +261,41 @@ static void HP_turn_off(void)
261} 261}
262#endif 262#endif
263 263
264static void i2s_codec_set_samplerate(unsigned int rate) 264void audiohw_mute(bool mute)
265{
266 if(mute)
267 REG_ICDC_CDCCR1 |= ICDC_CDCCR1_HPMUTE;
268 else
269 REG_ICDC_CDCCR1 &= ~ICDC_CDCCR1_HPMUTE;
270}
271
272void audiohw_preinit(void)
273{
274}
275
276void audiohw_postinit(void)
277{
278 audiohw_mute(false);
279 //HP_turn_on();
280}
281
282void audiohw_init(void)
283{
284 i2s_codec_init();
285}
286
287void audiohw_set_volume(int v)
288{
289 /* 0 <= v <= 60 */
290 unsigned int codec_volume = v / 20;
291 REG_ICDC_CDCCR2 = (REG_ICDC_CDCCR2 & ~ICDC_CDCCR2_HPVOL(0x3)) | ICDC_CDCCR2_HPVOL(codec_volume);
292}
293
294void audiohw_set_frequency(int freq)
265{ 295{
266 unsigned int speed; 296 unsigned int speed;
267 297
268 switch (rate) 298 switch(freq)
269 { 299 {
270 case 8000: 300 case 8000:
271 speed = ICDC_CDCCR2_SMPR(ICDC_CDCCR2_SMPR_8); 301 speed = ICDC_CDCCR2_SMPR(ICDC_CDCCR2_SMPR_8);
@@ -297,33 +327,6 @@ static void i2s_codec_set_samplerate(unsigned int rate)
297 default: 327 default:
298 return; 328 return;
299 } 329 }
300 REG_ICDC_CDCCR2 &= ~ICDC_CDCCR2_SMPR(0xF);
301 REG_ICDC_CDCCR2 |= speed;
302}
303 330
304void audiohw_mute(bool mute) 331 REG_ICDC_CDCCR2 = (REG_ICDC_CDCCR2 & ~ICDC_CDCCR2_SMPR(0xF)) | speed;
305{
306 if(mute)
307 REG_ICDC_CDCCR1 |= ICDC_CDCCR1_HPMUTE;
308 else
309 REG_ICDC_CDCCR1 &= ~ICDC_CDCCR1_HPMUTE;
310}
311
312void audiohw_preinit(void)
313{
314}
315
316void audiohw_postinit(void)
317{
318 audiohw_mute(false);
319}
320
321void audiohw_init(void)
322{
323 i2s_codec_init();
324}
325
326void audiohw_set_frequency(int freq)
327{
328 i2s_codec_set_samplerate(freq);
329} 332}
diff --git a/firmware/target/mips/ingenic_jz47xx/pcm-jz4740.c b/firmware/target/mips/ingenic_jz47xx/pcm-jz4740.c
index 11a5e6d8c0..05c89be158 100644
--- a/firmware/target/mips/ingenic_jz47xx/pcm-jz4740.c
+++ b/firmware/target/mips/ingenic_jz47xx/pcm-jz4740.c
@@ -37,12 +37,15 @@ static void* playback_address;
37void pcm_postinit(void) 37void pcm_postinit(void)
38{ 38{
39 audiohw_postinit(); 39 audiohw_postinit();
40 40
41 /* playback sample: 16 bits burst: 16 bytes */ 41 /* playback sample: 16 bits burst: 16 bytes */
42 __i2s_set_iss_sample_size(16); 42 __i2s_set_iss_sample_size(16);
43 __i2s_set_oss_sample_size(16); 43 __i2s_set_oss_sample_size(16);
44 __i2s_set_transmit_trigger(16 - 4); 44 __i2s_set_transmit_trigger(10);
45 __i2s_set_receive_trigger(4); 45 __i2s_set_receive_trigger(1);
46
47 /* Flush FIFO */
48 __aic_flush_fifo();
46} 49}
47 50
48void pcm_play_dma_init(void) 51void pcm_play_dma_init(void)
@@ -50,7 +53,7 @@ void pcm_play_dma_init(void)
50 /* TODO */ 53 /* TODO */
51 54
52 system_enable_irq(DMA_IRQ(DMA_AIC_TX_CHANNEL)); 55 system_enable_irq(DMA_IRQ(DMA_AIC_TX_CHANNEL));
53 56
54 /* Initialize default register values. */ 57 /* Initialize default register values. */
55 audiohw_init(); 58 audiohw_init();
56} 59}
@@ -63,30 +66,39 @@ void pcm_dma_apply_settings(void)
63 66
64static void play_start_pcm(void) 67static void play_start_pcm(void)
65{ 68{
66 /* Prefill FIFO */ 69 __aic_enable_transmit_dma();
67 REG_AIC_DR = 0; 70 __aic_enable_replay();
68 REG_AIC_DR = 0; 71
69 REG_AIC_DR = 0;
70 REG_AIC_DR = 0;
71
72 __i2s_enable_transmit_dma();
73 __i2s_enable_replay();
74
75 REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) |= DMAC_DCCSR_EN; 72 REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) |= DMAC_DCCSR_EN;
76 REG_DMAC_DCMD(DMA_AIC_TX_CHANNEL) |= DMAC_DCMD_TIE; 73
77
78 playback_started = true; 74 playback_started = true;
79} 75}
80 76
77static inline void set_dma(const void *addr, size_t size)
78{
79 logf("%x %x %d %d %x", (unsigned int)addr, size, (REG_AIC_SR>>24) & 0x20, (REG_AIC_SR>>8) & 0x20, REG_AIC_SR & 0xF);
80
81 //__dcache_writeback_all();
82 REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) = DMAC_DCCSR_NDES;
83 REG_DMAC_DSAR(DMA_AIC_TX_CHANNEL) = PHYSADDR((unsigned long)addr);
84 REG_DMAC_DTAR(DMA_AIC_TX_CHANNEL) = PHYSADDR((unsigned long)AIC_DR);
85 REG_DMAC_DTCR(DMA_AIC_TX_CHANNEL) = size / 16;
86 REG_DMAC_DRSR(DMA_AIC_TX_CHANNEL) = DMAC_DRSR_RS_AICOUT;
87 REG_DMAC_DCMD(DMA_AIC_TX_CHANNEL) = (DMAC_DCMD_SAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_DWDH_16 | DMAC_DCMD_TIE |
88 DMAC_DCMD_RDIL_IGN);
89
90 playback_address = (void*)addr;
91}
92
81static void play_stop_pcm(void) 93static void play_stop_pcm(void)
82{ 94{
83 REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) = (REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) | DMAC_DCCSR_HLT) & ~DMAC_DCCSR_EN; 95 REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) = (REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) | DMAC_DCCSR_HLT) & ~DMAC_DCCSR_EN;
84 96
85 dma_disable(); 97 dma_disable();
86 98
87 __i2s_disable_transmit_dma(); 99 __aic_disable_transmit_dma();
88 __i2s_disable_replay(); 100 __aic_disable_replay();
89 101
90 playback_started = false; 102 playback_started = false;
91} 103}
92 104
@@ -94,56 +106,47 @@ void pcm_play_dma_start(const void *addr, size_t size)
94{ 106{
95 dma_enable(); 107 dma_enable();
96 108
97 __dcache_writeback_all(); 109 set_dma(addr, size);
98 REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) = DMAC_DCCSR_NDES;
99 REG_DMAC_DSAR(DMA_AIC_TX_CHANNEL) = PHYSADDR((unsigned long)addr);
100 REG_DMAC_DTAR(DMA_AIC_TX_CHANNEL) = PHYSADDR((unsigned long)AIC_DR);
101 REG_DMAC_DTCR(DMA_AIC_TX_CHANNEL) = size;
102 REG_DMAC_DRSR(DMA_AIC_TX_CHANNEL) = DMAC_DRSR_RS_AICOUT;
103 REG_DMAC_DCMD(DMA_AIC_TX_CHANNEL) = (DMAC_DCMD_SAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_DWDH_16);
104
105 playback_address = (void*)addr;
106 play_start_pcm(); 110 play_start_pcm();
107} 111}
108 112
109 113
110static void play_dma_callback(void) 114static inline void play_dma_callback(void)
111{ 115{
112 unsigned char *start; 116 unsigned char *start;
113 size_t size = 0; 117 size_t size = 0;
114
115 pcm_callback_for_more(&start, &size); 118 pcm_callback_for_more(&start, &size);
116 if(size != 0) 119
120 if(LIKELY(size > 0))
117 { 121 {
118 __dcache_writeback_all(); 122 set_dma(start, size);
119 REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) = DMAC_DCCSR_NDES;
120 REG_DMAC_DSAR(DMA_AIC_TX_CHANNEL) = PHYSADDR((unsigned long)start);
121 REG_DMAC_DTAR(DMA_AIC_TX_CHANNEL) = PHYSADDR((unsigned long)AIC_DR);
122 REG_DMAC_DTCR(DMA_AIC_TX_CHANNEL) = size;
123 REG_DMAC_DRSR(DMA_AIC_TX_CHANNEL) = DMAC_DRSR_RS_AICOUT;
124 REG_DMAC_DCMD(DMA_AIC_TX_CHANNEL) = (DMAC_DCMD_SAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_DWDH_16);
125 REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) |= DMAC_DCCSR_EN; 123 REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) |= DMAC_DCCSR_EN;
126 REG_DMAC_DCMD(DMA_AIC_TX_CHANNEL) |= DMAC_DCMD_TIE;
127 return;
128 } 124 }
129 125 else
130 /* Error, callback missing or no more DMA to do */ 126 {
131 pcm_play_dma_stop(); 127 /* Error, callback missing or no more DMA to do */
132 pcm_play_dma_stopped_callback(); 128 pcm_play_dma_stop();
129 pcm_play_dma_stopped_callback();
130 }
133} 131}
134 132
135void DMA_CALLBACK(DMA_AIC_TX_CHANNEL)(void) 133void DMA_CALLBACK(DMA_AIC_TX_CHANNEL)(void)
136{ 134{
137 if (REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) & DMAC_DCCSR_AR) 135 if (REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) & DMAC_DCCSR_AR)
136 {
137 logf("PCM DMA address error");
138 REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) &= ~DMAC_DCCSR_AR; 138 REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) &= ~DMAC_DCCSR_AR;
139 }
139 140
140 if (REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) & DMAC_DCCSR_CT) 141 if (REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) & DMAC_DCCSR_HLT)
141 REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) &= ~DMAC_DCCSR_CT; 142 {
143 logf("PCM DMA halt");
144 REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) &= ~DMAC_DCCSR_HLT;
145 }
142 146
143 if (REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) & (DMAC_DCCSR_TT | DMAC_DCCSR_HLT)) 147 if (REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) & DMAC_DCCSR_TT)
144 { 148 {
145 REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) &= ~(DMAC_DCCSR_TT | DMAC_DCCSR_HLT); 149 REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) &= ~DMAC_DCCSR_TT;
146 REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) &= ~DMAC_DCCSR_EN;
147 play_dma_callback(); 150 play_dma_callback();
148 } 151 }
149} 152}
@@ -151,7 +154,7 @@ void DMA_CALLBACK(DMA_AIC_TX_CHANNEL)(void)
151size_t pcm_get_bytes_waiting(void) 154size_t pcm_get_bytes_waiting(void)
152{ 155{
153 if(playback_started) 156 if(playback_started)
154 return REG_DMAC_DTCR(DMA_AIC_TX_CHANNEL) & ~3; 157 return (REG_DMAC_DTCR(DMA_AIC_TX_CHANNEL) * 16) & ~3;
155 else 158 else
156 return 0; 159 return 0;
157} 160}
@@ -161,8 +164,8 @@ const void * pcm_play_dma_get_peak_buffer(int *count)
161 /* TODO */ 164 /* TODO */
162 if(playback_started) 165 if(playback_started)
163 { 166 {
164 *count = REG_DMAC_DTCR(DMA_AIC_TX_CHANNEL); 167 *count = REG_DMAC_DTCR(DMA_AIC_TX_CHANNEL) >> 2;
165 return (void*)(playback_address + ((REG_DMAC_DTCR(DMA_AIC_TX_CHANNEL) + 2) & ~3)); 168 return (void*)(playback_address + ((REG_DMAC_DTCR(DMA_AIC_TX_CHANNEL)*16 + 2) & ~3));
166 } 169 }
167 else 170 else
168 { 171 {
@@ -174,7 +177,7 @@ const void * pcm_play_dma_get_peak_buffer(int *count)
174void pcm_play_dma_stop(void) 177void pcm_play_dma_stop(void)
175{ 178{
176 play_stop_pcm(); 179 play_stop_pcm();
177 180
178 /* TODO */ 181 /* TODO */
179} 182}
180 183
@@ -191,9 +194,9 @@ void pcm_play_unlock(void)
191void pcm_play_dma_pause(bool pause) 194void pcm_play_dma_pause(bool pause)
192{ 195{
193 if(pause) 196 if(pause)
194 play_stop_pcm(); 197 REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) &= ~DMAC_DCCSR_EN;
195 else 198 else
196 play_start_pcm(); 199 REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) |= DMAC_DCCSR_EN;
197} 200}
198 201
199void audiohw_close(void) 202void audiohw_close(void)
diff --git a/firmware/target/mips/ingenic_jz47xx/system-target.h b/firmware/target/mips/ingenic_jz47xx/system-target.h
index 08c3aeddb6..b2d960ef54 100644
--- a/firmware/target/mips/ingenic_jz47xx/system-target.h
+++ b/firmware/target/mips/ingenic_jz47xx/system-target.h
@@ -86,10 +86,10 @@ void mdelay(unsigned int msec);
86void dma_enable(void); 86void dma_enable(void);
87void dma_disable(void); 87void dma_disable(void);
88 88
89#define DMA_LCD_CHANNEL 0 89#define DMA_AIC_TX_CHANNEL 0
90#define DMA_NAND_CHANNEL 1 90#define DMA_NAND_CHANNEL 1
91#define DMA_USB_CHANNEL 2 91#define DMA_USB_CHANNEL 2
92#define DMA_AIC_TX_CHANNEL 3 92#define DMA_LCD_CHANNEL 3
93 93
94#define XDMA_CALLBACK(n) DMA ## n 94#define XDMA_CALLBACK(n) DMA ## n
95#define DMA_CALLBACK(n) XDMA_CALLBACK(n) 95#define DMA_CALLBACK(n) XDMA_CALLBACK(n)