diff options
author | Aidan MacDonald <amachronic@protonmail.com> | 2021-05-30 19:56:44 +0100 |
---|---|---|
committer | Aidan MacDonald <amachronic@protonmail.com> | 2021-05-30 19:17:50 +0000 |
commit | f63edb52ef8ecf18520926b40b3c61db37081a9d (patch) | |
tree | 29c36d3f247d7bab2f547d76655ac81fa8a71946 /firmware/target | |
parent | c78ba1aa689b178ebb73b2730bc1b13697371fbf (diff) | |
download | rockbox-f63edb52ef8ecf18520926b40b3c61db37081a9d.tar.gz rockbox-f63edb52ef8ecf18520926b40b3c61db37081a9d.zip |
x1000: refactor AIC initialization
Have pcm-x1000 handle most work, so target's audiohw code touches
only the relevant settings.
Change-Id: Icf3d1b7ca428ac50a5a16ecec39ed8186ac5ae13
Diffstat (limited to 'firmware/target')
-rw-r--r-- | firmware/target/mips/ingenic_x1000/aic-x1000.c | 132 | ||||
-rw-r--r-- | firmware/target/mips/ingenic_x1000/aic-x1000.h | 130 | ||||
-rw-r--r-- | firmware/target/mips/ingenic_x1000/dma-x1000.h | 5 | ||||
-rw-r--r-- | firmware/target/mips/ingenic_x1000/fiiom3k/audiohw-fiiom3k.c | 26 | ||||
-rw-r--r-- | firmware/target/mips/ingenic_x1000/pcm-x1000.c | 100 | ||||
-rw-r--r-- | firmware/target/mips/ingenic_x1000/x1000/aic.h | 12 |
6 files changed, 321 insertions, 84 deletions
diff --git a/firmware/target/mips/ingenic_x1000/aic-x1000.c b/firmware/target/mips/ingenic_x1000/aic-x1000.c index a0e509d3b6..1d1768d4f9 100644 --- a/firmware/target/mips/ingenic_x1000/aic-x1000.c +++ b/firmware/target/mips/ingenic_x1000/aic-x1000.c | |||
@@ -31,12 +31,12 @@ | |||
31 | * is complete if this value is less than "cnt", and may be incomplete if it | 31 | * is complete if this value is less than "cnt", and may be incomplete if it |
32 | * is equal to "cnt". (Note the leading zero term is not written to "buf".) | 32 | * is equal to "cnt". (Note the leading zero term is not written to "buf".) |
33 | */ | 33 | */ |
34 | static unsigned cf_derive(unsigned m, unsigned n, unsigned* buf, unsigned cnt) | 34 | static uint32_t cf_derive(uint32_t m, uint32_t n, uint32_t* buf, uint32_t cnt) |
35 | { | 35 | { |
36 | unsigned wrote = 0; | 36 | uint32_t wrote = 0; |
37 | unsigned a = m / n; | 37 | uint32_t a = m / n; |
38 | while(cnt--) { | 38 | while(cnt--) { |
39 | unsigned tmp = n; | 39 | uint32_t tmp = n; |
40 | n = m - n * a; | 40 | n = m - n * a; |
41 | if(n == 0) | 41 | if(n == 0) |
42 | break; | 42 | break; |
@@ -54,16 +54,16 @@ static unsigned cf_derive(unsigned m, unsigned n, unsigned* buf, unsigned cnt) | |||
54 | * calculate the rational number m/n which it represents. Returns m and n. | 54 | * calculate the rational number m/n which it represents. Returns m and n. |
55 | * If count is zero, then m and n are undefined. | 55 | * If count is zero, then m and n are undefined. |
56 | */ | 56 | */ |
57 | static void cf_expand(const unsigned* buf, unsigned count, | 57 | static void cf_expand(const uint32_t* buf, uint32_t count, |
58 | unsigned* m, unsigned* n) | 58 | uint32_t* m, uint32_t* n) |
59 | { | 59 | { |
60 | if(count == 0) | 60 | if(count == 0) |
61 | return; | 61 | return; |
62 | 62 | ||
63 | unsigned i = count - 1; | 63 | uint32_t i = count - 1; |
64 | unsigned mx = 1, nx = buf[i]; | 64 | uint32_t mx = 1, nx = buf[i]; |
65 | while(i--) { | 65 | while(i--) { |
66 | unsigned tmp = nx; | 66 | uint32_t tmp = nx; |
67 | nx = mx + buf[i] * nx; | 67 | nx = mx + buf[i] * nx; |
68 | mx = tmp; | 68 | mx = tmp; |
69 | } | 69 | } |
@@ -72,48 +72,102 @@ static void cf_expand(const unsigned* buf, unsigned count, | |||
72 | *n = nx; | 72 | *n = nx; |
73 | } | 73 | } |
74 | 74 | ||
75 | int aic_i2s_set_mclk(x1000_clk_t clksrc, unsigned fs, unsigned mult) | 75 | static int calc_i2s_clock_params(x1000_clk_t clksrc, |
76 | uint32_t fs, uint32_t mult, | ||
77 | uint32_t* div_m, uint32_t* div_n, | ||
78 | uint32_t* i2sdiv) | ||
76 | { | 79 | { |
77 | /* get the input clock rate */ | 80 | if(clksrc == X1000_CLK_EXCLK) { |
78 | uint32_t src_freq = clk_get(clksrc); | 81 | /* EXCLK mode bypasses the CPM clock so it's more limited */ |
82 | *div_m = 0; | ||
83 | *div_n = 0; | ||
84 | *i2sdiv = X1000_EXCLK_FREQ / 64 / fs; | ||
85 | |||
86 | /* clamp to maximum value */ | ||
87 | if(*i2sdiv > 0x200) | ||
88 | *i2sdiv = 0x200; | ||
89 | |||
90 | return 0; | ||
91 | } | ||
79 | 92 | ||
80 | /* reject invalid parameters */ | 93 | /* ensure a valid clock was selected */ |
94 | if(clksrc != X1000_CLK_SCLK_A && | ||
95 | clksrc != X1000_CLK_MPLL) | ||
96 | return -1; | ||
97 | |||
98 | /* ensure bit clock constraint is respected */ | ||
81 | if(mult % 64 != 0) | 99 | if(mult % 64 != 0) |
82 | return -1; | 100 | return -1; |
83 | 101 | ||
84 | if(clksrc == X1000_EXCLK_FREQ) { | 102 | /* ensure master clock frequency is not too high */ |
85 | if(mult != 0) | 103 | if(fs > UINT32_MAX/mult) |
86 | return -1; | 104 | return -1; |
105 | |||
106 | /* get frequencies */ | ||
107 | uint32_t tgt_freq = fs * mult; | ||
108 | uint32_t src_freq = clk_get(clksrc); | ||
109 | |||
110 | /* calculate best rational approximation fitting hardware constraints */ | ||
111 | uint32_t m = 0, n = 0; | ||
112 | uint32_t buf[16]; | ||
113 | uint32_t cnt = cf_derive(tgt_freq, src_freq, &buf[0], 16); | ||
114 | do { | ||
115 | cf_expand(&buf[0], cnt, &m, &n); | ||
116 | cnt -= 1; | ||
117 | } while(cnt > 0 && (m > 512 || n > 8192) && (n >= 2*m)); | ||
87 | 118 | ||
88 | jz_writef(AIC_I2SCR, STPBK(1)); | 119 | /* unrepresentable */ |
120 | if(cnt == 0 || n == 0 || m == 0) | ||
121 | return -1; | ||
122 | |||
123 | *div_m = m; | ||
124 | *div_n = n; | ||
125 | *i2sdiv = mult / 64; | ||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | uint32_t aic_calc_i2s_clock(x1000_clk_t clksrc, uint32_t fs, uint32_t mult) | ||
130 | { | ||
131 | uint32_t m, n, i2sdiv; | ||
132 | if(calc_i2s_clock_params(clksrc, fs, mult, &m, &n, &i2sdiv)) | ||
133 | return 0; | ||
134 | |||
135 | unsigned long long rate = clk_get(clksrc); | ||
136 | rate *= m; | ||
137 | rate /= n * i2sdiv; /* this multiply can't overflow. */ | ||
138 | |||
139 | /* clamp */ | ||
140 | if(rate > 0xffffffffull) | ||
141 | rate = 0xffffffff; | ||
142 | |||
143 | return rate; | ||
144 | } | ||
145 | |||
146 | int aic_set_i2s_clock(x1000_clk_t clksrc, uint32_t fs, uint32_t mult) | ||
147 | { | ||
148 | uint32_t m, n, i2sdiv; | ||
149 | if(calc_i2s_clock_params(clksrc, fs, mult, &m, &n, &i2sdiv)) | ||
150 | return -1; | ||
151 | |||
152 | /* turn off bit clock */ | ||
153 | bool bitclock_en = !jz_readf(AIC_I2SCR, STPBK); | ||
154 | jz_writef(AIC_I2SCR, STPBK(1)); | ||
155 | |||
156 | /* handle master clock */ | ||
157 | if(clksrc == X1000_CLK_EXCLK) { | ||
89 | jz_writef(CPM_I2SCDR, CS(0), CE(0)); | 158 | jz_writef(CPM_I2SCDR, CS(0), CE(0)); |
90 | REG_AIC_I2SDIV = X1000_EXCLK_FREQ / 64 / fs; | ||
91 | } else { | 159 | } else { |
92 | if(mult == 0) | ||
93 | return -1; | ||
94 | if(fs*mult > src_freq) | ||
95 | return -1; | ||
96 | |||
97 | /* calculate best rational approximation that fits our constraints */ | ||
98 | unsigned m = 0, n = 0; | ||
99 | unsigned buf[16]; | ||
100 | unsigned cnt = cf_derive(fs*mult, src_freq, &buf[0], 16); | ||
101 | do { | ||
102 | cf_expand(&buf[0], cnt, &m, &n); | ||
103 | cnt -= 1; | ||
104 | } while(cnt > 0 && (m > 512 || n > 8192) && (n >= 2*m)); | ||
105 | |||
106 | /* wrong values */ | ||
107 | if(cnt == 0 || n == 0 || m == 0) | ||
108 | return -1; | ||
109 | |||
110 | jz_writef(AIC_I2SCR, STPBK(1)); | ||
111 | jz_writef(CPM_I2SCDR, PCS(clksrc == X1000_CLK_MPLL ? 1 : 0), | 160 | jz_writef(CPM_I2SCDR, PCS(clksrc == X1000_CLK_MPLL ? 1 : 0), |
112 | CS(1), CE(1), DIV_M(m), DIV_N(n)); | 161 | CS(1), CE(1), DIV_M(m), DIV_N(n)); |
113 | jz_write(CPM_I2SCDR1, REG_CPM_I2SCDR1); | 162 | jz_write(CPM_I2SCDR1, REG_CPM_I2SCDR1); |
114 | REG_AIC_I2SDIV = (mult / 64) - 1; | ||
115 | } | 163 | } |
116 | 164 | ||
117 | jz_writef(AIC_I2SCR, STPBK(0)); | 165 | /* set bit clock divider */ |
166 | REG_AIC_I2SDIV = i2sdiv - 1; | ||
167 | |||
168 | /* re-enable the bit clock */ | ||
169 | if(bitclock_en) | ||
170 | jz_writef(AIC_I2SCR, STPBK(0)); | ||
171 | |||
118 | return 0; | 172 | return 0; |
119 | } | 173 | } |
diff --git a/firmware/target/mips/ingenic_x1000/aic-x1000.h b/firmware/target/mips/ingenic_x1000/aic-x1000.h index eda0f80f04..f272655b9c 100644 --- a/firmware/target/mips/ingenic_x1000/aic-x1000.h +++ b/firmware/target/mips/ingenic_x1000/aic-x1000.h | |||
@@ -23,24 +23,122 @@ | |||
23 | #define __AIC_X1000_H__ | 23 | #define __AIC_X1000_H__ |
24 | 24 | ||
25 | #include "clk-x1000.h" | 25 | #include "clk-x1000.h" |
26 | #include "x1000/aic.h" | ||
26 | #include <stdbool.h> | 27 | #include <stdbool.h> |
28 | #include <stdint.h> | ||
27 | 29 | ||
28 | /* Set frequency of I2S master clock supplied by AIC. Has no use if an | 30 | #define AIC_I2S_MASTER_MODE 0 |
29 | * external DAC is supplying the master clock. Must be called with the | 31 | #define AIC_I2S_MASTER_EXCLK_MODE 1 |
30 | * bit clock disabled. | 32 | #define AIC_I2S_SLAVE_MODE 2 |
31 | * | 33 | |
32 | * - clksrc can be one of EXCLK, SCLK_A, MPLL. | 34 | #define AIC_I2S_LEFT_CHANNEL_FIRST 0 |
33 | * - This function does not modify PLL settings. It's the caller's job | 35 | #define AIC_I2S_RIGHT_CHANNEL_FIRST 1 |
34 | * to ensure the PLL is configured and runing. | 36 | |
35 | * - fs is the audio sampling frequency (8 KHz - 192 KHz) | 37 | /* Nb. the functions below are intended to serve as "documentation" and make |
36 | * - mult is multiplied by fs to get the master clock rate. | 38 | * target audiohw code clearer, they should normally be called with immediate |
37 | * - mult must be a multiple of 64 due to AIC bit clock requirements. | 39 | * constant arguments so they are inlined to a register read-modify-write. */ |
38 | * - Note: EXCLK bypasses the decimal divider so it is not very flexible. | 40 | |
39 | * If using EXCLK you must set mult=0. If EXCLK is not a multiple of | 41 | /* Enable/disable some kind of big-endian mode. Presumably it refers to |
40 | * the bit clock (= 64*fs), then the clock rate will be inaccurate. | 42 | * the endianness of the samples read or written to the FIFO. */ |
41 | * | 43 | static inline void aic_set_big_endian_format(bool en) |
42 | * Returns zero on success and nonzero if the frequency is not achievable. | 44 | { |
45 | jz_writef(AIC_CFG, MSB(en ? 1 : 0)); | ||
46 | } | ||
47 | |||
48 | /* Set whether to send the last sample (true) or a zero sample (false) | ||
49 | * if the AIC FIFO underflows during playback. */ | ||
50 | static inline void aic_set_play_last_sample(bool en) | ||
51 | { | ||
52 | jz_writef(AIC_CFG, LSMP(en ? 1 : 0)); | ||
53 | } | ||
54 | |||
55 | /* Select the use of the internal or external codec. */ | ||
56 | static inline void aic_set_external_codec(bool en) | ||
57 | { | ||
58 | jz_writef(AIC_CFG, ICDC(en ? 0 : 1)); | ||
59 | } | ||
60 | |||
61 | /* Set I2S interface mode */ | ||
62 | static inline void aic_set_i2s_mode(int mode) | ||
63 | { | ||
64 | switch(mode) { | ||
65 | default: | ||
66 | case AIC_I2S_MASTER_MODE: | ||
67 | jz_writef(AIC_CFG, BCKD(1), SYNCD(1)); | ||
68 | break; | ||
69 | |||
70 | case AIC_I2S_MASTER_EXCLK_MODE: | ||
71 | jz_writef(AIC_CFG, BCKD(0), SYNCD(1)); | ||
72 | break; | ||
73 | |||
74 | case AIC_I2S_SLAVE_MODE: | ||
75 | jz_writef(AIC_CFG, BCKD(0), SYNCD(0)); | ||
76 | break; | ||
77 | } | ||
78 | } | ||
79 | |||
80 | /* Select the channel ordering on the I2S interface (playback only). */ | ||
81 | static inline void aic_set_i2s_channel_order(int order) | ||
82 | { | ||
83 | switch(order) { | ||
84 | default: | ||
85 | case AIC_I2S_LEFT_CHANNEL_FIRST: | ||
86 | jz_writef(AIC_I2SCR, RFIRST(0)); | ||
87 | break; | ||
88 | |||
89 | case AIC_I2S_RIGHT_CHANNEL_FIRST: | ||
90 | jz_writef(AIC_I2SCR, RFIRST(1)); | ||
91 | break; | ||
92 | } | ||
93 | } | ||
94 | |||
95 | /* Enable/disable the I2S master clock (also called 'system clock') */ | ||
96 | static inline void aic_enable_i2s_master_clock(bool en) | ||
97 | { | ||
98 | jz_writef(AIC_I2SCR, ESCLK(en ? 1 : 0)); | ||
99 | } | ||
100 | |||
101 | /* Enable/disable the I2S bit clock */ | ||
102 | static inline void aic_enable_i2s_bit_clock(bool en) | ||
103 | { | ||
104 | jz_writef(AIC_I2SCR, STPBK(en ? 0 : 1)); | ||
105 | } | ||
106 | |||
107 | /* Select whether I2S mode is used (false) or MSB-justified mode (true). */ | ||
108 | static inline void aic_set_msb_justified_mode(bool en) | ||
109 | { | ||
110 | jz_writef(AIC_I2SCR, AMSL(en ? 1 : 0)); | ||
111 | } | ||
112 | |||
113 | /* Calculate frequency of I2S clocks. | ||
114 | * | ||
115 | * - 'clksrc' can be one of EXCLK, SCLK_A, or MPLL. | ||
116 | * - 'fs' is the audio sampling frequency in Hz, must be 8 KHz - 192 KHz. | ||
117 | * - The master clock frequency equals 'mult * fs' Hz. Due to hardware | ||
118 | * restrictions, 'mult' must be divisible by 64. | ||
119 | * | ||
120 | * - NOTE: When using EXCLK source, the master clock equals EXCLK and the | ||
121 | * 'mult' parameter is ignored. | ||
122 | * | ||
123 | * This function returns the actual bit clock rate which would be achieved. | ||
124 | * (Note the bit clock is always 64x the effective sampling rate.) | ||
125 | * | ||
126 | * If the exact rate cannot be attained, then this will return the closest | ||
127 | * possible rate to the desired rate. In case of invalid parameters, this | ||
128 | * function will return zero. That also occurs if the chosen PLL is stopped. | ||
129 | */ | ||
130 | extern uint32_t aic_calc_i2s_clock(x1000_clk_t clksrc, | ||
131 | uint32_t fs, uint32_t mult); | ||
132 | |||
133 | /* Set the I2S clock frequency. | ||
134 | * | ||
135 | * Parameters are the same as 'aic_calc_i2s_clock()' except this function | ||
136 | * will set the clocks. If the bit clock is running, it will be automatically | ||
137 | * stopped and restarted properly. | ||
138 | * | ||
139 | * Returns zero on success. If an invalid state occurs (due to bad settings) | ||
140 | * then this function will do nothing and return a nonzero value. | ||
43 | */ | 141 | */ |
44 | extern int aic_i2s_set_mclk(x1000_clk_t clksrc, unsigned fs, unsigned mult); | 142 | extern int aic_set_i2s_clock(x1000_clk_t clksrc, uint32_t fs, uint32_t mult); |
45 | 143 | ||
46 | #endif /* __AIC_X1000_H__ */ | 144 | #endif /* __AIC_X1000_H__ */ |
diff --git a/firmware/target/mips/ingenic_x1000/dma-x1000.h b/firmware/target/mips/ingenic_x1000/dma-x1000.h index d836a0cf54..8bb5f1ddaa 100644 --- a/firmware/target/mips/ingenic_x1000/dma-x1000.h +++ b/firmware/target/mips/ingenic_x1000/dma-x1000.h | |||
@@ -43,8 +43,9 @@ | |||
43 | * cannot be used safely. | 43 | * cannot be used safely. |
44 | */ | 44 | */ |
45 | #define DMA_CHANNEL_AUDIO 0 | 45 | #define DMA_CHANNEL_AUDIO 0 |
46 | #define DMA_CHANNEL_FBCOPY 1 | 46 | #define DMA_CHANNEL_RECORD 1 |
47 | #define DMA_NUM_USED_CHANNELS 2 | 47 | #define DMA_CHANNEL_FBCOPY 2 |
48 | #define DMA_NUM_USED_CHANNELS 3 | ||
48 | 49 | ||
49 | struct dma_desc { | 50 | struct dma_desc { |
50 | uint32_t cm; /* meaning and layout same as DMA_CHN_CM */ | 51 | uint32_t cm; /* meaning and layout same as DMA_CHN_CM */ |
diff --git a/firmware/target/mips/ingenic_x1000/fiiom3k/audiohw-fiiom3k.c b/firmware/target/mips/ingenic_x1000/fiiom3k/audiohw-fiiom3k.c index 2f43809523..d1c4d67d33 100644 --- a/firmware/target/mips/ingenic_x1000/fiiom3k/audiohw-fiiom3k.c +++ b/firmware/target/mips/ingenic_x1000/fiiom3k/audiohw-fiiom3k.c | |||
@@ -26,22 +26,13 @@ | |||
26 | #include "aic-x1000.h" | 26 | #include "aic-x1000.h" |
27 | #include "i2c-x1000.h" | 27 | #include "i2c-x1000.h" |
28 | #include "gpio-x1000.h" | 28 | #include "gpio-x1000.h" |
29 | #include "x1000/aic.h" | ||
30 | #include "x1000/cpm.h" | ||
31 | 29 | ||
32 | void audiohw_init(void) | 30 | void audiohw_init(void) |
33 | { | 31 | { |
34 | /* Configure AIC for I2S operation */ | 32 | /* Configure AIC */ |
35 | jz_writef(CPM_CLKGR, AIC(0)); | 33 | aic_set_external_codec(true); |
36 | gpio_config(GPIO_B, 0x1f, GPIO_DEVICE(1)); | 34 | aic_set_i2s_mode(AIC_I2S_MASTER_MODE); |
37 | jz_writef(AIC_I2SCR, STPBK(1)); | 35 | aic_enable_i2s_master_clock(true); |
38 | |||
39 | /* Operate as I2S master, use external codec */ | ||
40 | jz_writef(AIC_CFG, AUSEL(1), ICDC(0), BCKD(1), SYNCD(1), LSMP(1)); | ||
41 | jz_writef(AIC_I2SCR, ESCLK(1), AMSL(0)); | ||
42 | |||
43 | /* Stereo audio, packed 16 bit samples */ | ||
44 | jz_writef(AIC_CCR, PACK16(1), CHANNEL(1), OSS(1)); | ||
45 | 36 | ||
46 | /* Initialize DAC */ | 37 | /* Initialize DAC */ |
47 | i2c_x1000_set_freq(AK4376_BUS, I2C_FREQ_400K); | 38 | i2c_x1000_set_freq(AK4376_BUS, I2C_FREQ_400K); |
@@ -64,18 +55,15 @@ void ak4376_set_pdn_pin(int level) | |||
64 | 55 | ||
65 | int ak4376_set_mclk_freq(int hw_freq, bool enabled) | 56 | int ak4376_set_mclk_freq(int hw_freq, bool enabled) |
66 | { | 57 | { |
67 | /* Get the multiplier */ | ||
68 | int freq = hw_freq_sampr[hw_freq]; | 58 | int freq = hw_freq_sampr[hw_freq]; |
69 | int mult = freq >= SAMPR_176 ? 128 : 256; | 59 | int mult = freq >= SAMPR_176 ? 128 : 256; |
70 | 60 | ||
71 | if(enabled) { | 61 | if(enabled) { |
72 | /* Set the new frequency; clock is enabled afterward */ | 62 | if(aic_set_i2s_clock(X1000_CLK_SCLK_A, freq, mult)) { |
73 | if(aic_i2s_set_mclk(X1000_CLK_SCLK_A, freq, mult)) | ||
74 | logf("WARNING: unachievable audio rate %d x %d!?", freq, mult); | 63 | logf("WARNING: unachievable audio rate %d x %d!?", freq, mult); |
75 | } else { | 64 | } |
76 | /* Shut off the clock */ | ||
77 | jz_writef(AIC_I2SCR, STPBK(1)); | ||
78 | } | 65 | } |
79 | 66 | ||
67 | aic_enable_i2s_bit_clock(enabled); | ||
80 | return mult; | 68 | return mult; |
81 | } | 69 | } |
diff --git a/firmware/target/mips/ingenic_x1000/pcm-x1000.c b/firmware/target/mips/ingenic_x1000/pcm-x1000.c index 9ae6f5a956..fd5e9d20c8 100644 --- a/firmware/target/mips/ingenic_x1000/pcm-x1000.c +++ b/firmware/target/mips/ingenic_x1000/pcm-x1000.c | |||
@@ -21,13 +21,16 @@ | |||
21 | 21 | ||
22 | #include "system.h" | 22 | #include "system.h" |
23 | #include "kernel.h" | 23 | #include "kernel.h" |
24 | #include "audio.h" | ||
24 | #include "audiohw.h" | 25 | #include "audiohw.h" |
25 | #include "pcm.h" | 26 | #include "pcm.h" |
26 | #include "pcm-internal.h" | 27 | #include "pcm-internal.h" |
27 | #include "panic.h" | 28 | #include "panic.h" |
28 | #include "dma-x1000.h" | 29 | #include "dma-x1000.h" |
29 | #include "irq-x1000.h" | 30 | #include "irq-x1000.h" |
31 | #include "gpio-x1000.h" | ||
30 | #include "x1000/aic.h" | 32 | #include "x1000/aic.h" |
33 | #include "x1000/cpm.h" | ||
31 | 34 | ||
32 | #define AIC_STATE_STOPPED 0 | 35 | #define AIC_STATE_STOPPED 0 |
33 | #define AIC_STATE_PLAYING 1 | 36 | #define AIC_STATE_PLAYING 1 |
@@ -41,21 +44,45 @@ static volatile int aic_dma_pending_event = DMA_EVENT_NONE; | |||
41 | 44 | ||
42 | static dma_desc aic_dma_desc; | 45 | static dma_desc aic_dma_desc; |
43 | 46 | ||
44 | static void pcm_dma_int_cb(int event); | 47 | static void pcm_play_dma_int_cb(int event); |
48 | #ifdef HAVE_RECORDING | ||
49 | static void pcm_rec_dma_int_cb(int event); | ||
50 | #endif | ||
45 | 51 | ||
46 | void pcm_play_dma_init(void) | 52 | void pcm_play_dma_init(void) |
47 | { | 53 | { |
54 | /* Ungate clock, assign pins. NB this overlaps with pins labeled "sa0-sa4" | ||
55 | * on Ingenic's datasheets but I'm not sure what they are. Probably safe to | ||
56 | * assume they are not useful to Rockbox... */ | ||
57 | jz_writef(CPM_CLKGR, AIC(0)); | ||
58 | gpio_config(GPIO_B, 0x1f, GPIO_DEVICE(1)); | ||
59 | |||
60 | /* Configure AIC with some sane defaults */ | ||
61 | jz_writef(AIC_CFG, RST(1)); | ||
62 | jz_writef(AIC_I2SCR, STPBK(1)); | ||
63 | jz_writef(AIC_CFG, MSB(0), LSMP(1), ICDC(0), AUSEL(1), BCKD(0), SYNCD(0)); | ||
64 | jz_writef(AIC_CCR, ENDSW(0), ASVTSU(0)); | ||
65 | jz_writef(AIC_I2SCR, RFIRST(0), ESCLK(0), AMSL(0)); | ||
66 | jz_write(AIC_SPENA, 0); | ||
67 | |||
48 | /* Let the target initialize its hardware and setup the AIC */ | 68 | /* Let the target initialize its hardware and setup the AIC */ |
49 | audiohw_init(); | 69 | audiohw_init(); |
50 | 70 | ||
51 | /* Set DMA callback */ | 71 | /* Program audio format (stereo, packed 16 bit samples) */ |
52 | dma_set_callback(DMA_CHANNEL_AUDIO, pcm_dma_int_cb); | 72 | jz_writef(AIC_CCR, PACK16(1), CHANNEL_V(STEREO), |
73 | OSS_V(16BIT), ISS_V(16BIT), M2S(0)); | ||
74 | jz_writef(AIC_I2SCR, SWLH(0)); | ||
53 | 75 | ||
54 | /* Program FIFO threshold -- DMA settings must match */ | 76 | /* Set DMA settings */ |
55 | jz_writef(AIC_CFG, TFTH(16)); | 77 | jz_writef(AIC_CFG, TFTH(16), RFTH(16)); |
78 | dma_set_callback(DMA_CHANNEL_AUDIO, pcm_play_dma_int_cb); | ||
79 | #ifdef HAVE_RECORDING | ||
80 | dma_set_callback(DMA_CHANNEL_RECORD, pcm_rec_dma_int_cb); | ||
81 | #endif | ||
56 | 82 | ||
57 | /* Ensure all playback is disabled */ | 83 | /* Mask all interrupts and disable playback/recording */ |
58 | jz_writef(AIC_CCR, ERPL(0)); | 84 | jz_writef(AIC_CCR, EROR(0), ETUR(0), ERFS(0), ETFS(0), |
85 | ENLBF(0), ERPL(0), EREC(0)); | ||
59 | 86 | ||
60 | /* Enable the controller */ | 87 | /* Enable the controller */ |
61 | jz_writef(AIC_CFG, ENABLE(1)); | 88 | jz_writef(AIC_CFG, ENABLE(1)); |
@@ -112,7 +139,7 @@ static void pcm_dma_handle_event(int event) | |||
112 | } | 139 | } |
113 | } | 140 | } |
114 | 141 | ||
115 | static void pcm_dma_int_cb(int event) | 142 | static void pcm_play_dma_int_cb(int event) |
116 | { | 143 | { |
117 | if(aic_lock) { | 144 | if(aic_lock) { |
118 | aic_dma_pending_event = event; | 145 | aic_dma_pending_event = event; |
@@ -156,6 +183,63 @@ void pcm_play_unlock(void) | |||
156 | restore_irq(irq); | 183 | restore_irq(irq); |
157 | } | 184 | } |
158 | 185 | ||
186 | #ifdef HAVE_RECORDING | ||
187 | /* | ||
188 | * Recording | ||
189 | */ | ||
190 | |||
191 | /* FIXME need to implement this!! */ | ||
192 | |||
193 | static void pcm_rec_dma_int_cb(int event) | ||
194 | { | ||
195 | (void)event; | ||
196 | } | ||
197 | |||
198 | void pcm_rec_dma_init(void) | ||
199 | { | ||
200 | } | ||
201 | |||
202 | void pcm_rec_dma_close(void) | ||
203 | { | ||
204 | } | ||
205 | |||
206 | void pcm_rec_dma_start(void* addr, size_t size) | ||
207 | { | ||
208 | (void)addr; | ||
209 | (void)size; | ||
210 | } | ||
211 | |||
212 | void pcm_rec_dma_stop(void) | ||
213 | { | ||
214 | } | ||
215 | |||
216 | void pcm_rec_lock(void) | ||
217 | { | ||
218 | |||
219 | } | ||
220 | |||
221 | void pcm_rec_unlock(void) | ||
222 | { | ||
223 | |||
224 | } | ||
225 | |||
226 | const void* pcm_rec_dma_get_peak_buffer(void) | ||
227 | { | ||
228 | return NULL; | ||
229 | } | ||
230 | |||
231 | void audio_set_output_source(int source) | ||
232 | { | ||
233 | (void)source; | ||
234 | } | ||
235 | |||
236 | void audio_input_mux(int source, unsigned flags) | ||
237 | { | ||
238 | (void)source; | ||
239 | (void)flags; | ||
240 | } | ||
241 | #endif /* HAVE_RECORDING */ | ||
242 | |||
159 | void AIC(void) | 243 | void AIC(void) |
160 | { | 244 | { |
161 | if(jz_readf(AIC_SR, TUR)) { | 245 | if(jz_readf(AIC_SR, TUR)) { |
diff --git a/firmware/target/mips/ingenic_x1000/x1000/aic.h b/firmware/target/mips/ingenic_x1000/x1000/aic.h index d212ddc4e1..5f5e771c2c 100644 --- a/firmware/target/mips/ingenic_x1000/x1000/aic.h +++ b/firmware/target/mips/ingenic_x1000/x1000/aic.h | |||
@@ -123,18 +123,30 @@ | |||
123 | #define JI_AIC_CCR | 123 | #define JI_AIC_CCR |
124 | #define BP_AIC_CCR_CHANNEL 24 | 124 | #define BP_AIC_CCR_CHANNEL 24 |
125 | #define BM_AIC_CCR_CHANNEL 0x7000000 | 125 | #define BM_AIC_CCR_CHANNEL 0x7000000 |
126 | #define BV_AIC_CCR_CHANNEL__MONO 0x0 | ||
127 | #define BV_AIC_CCR_CHANNEL__STEREO 0x1 | ||
126 | #define BF_AIC_CCR_CHANNEL(v) (((v) & 0x7) << 24) | 128 | #define BF_AIC_CCR_CHANNEL(v) (((v) & 0x7) << 24) |
127 | #define BFM_AIC_CCR_CHANNEL(v) BM_AIC_CCR_CHANNEL | 129 | #define BFM_AIC_CCR_CHANNEL(v) BM_AIC_CCR_CHANNEL |
128 | #define BF_AIC_CCR_CHANNEL_V(e) BF_AIC_CCR_CHANNEL(BV_AIC_CCR_CHANNEL__##e) | 130 | #define BF_AIC_CCR_CHANNEL_V(e) BF_AIC_CCR_CHANNEL(BV_AIC_CCR_CHANNEL__##e) |
129 | #define BFM_AIC_CCR_CHANNEL_V(v) BM_AIC_CCR_CHANNEL | 131 | #define BFM_AIC_CCR_CHANNEL_V(v) BM_AIC_CCR_CHANNEL |
130 | #define BP_AIC_CCR_OSS 19 | 132 | #define BP_AIC_CCR_OSS 19 |
131 | #define BM_AIC_CCR_OSS 0x380000 | 133 | #define BM_AIC_CCR_OSS 0x380000 |
134 | #define BV_AIC_CCR_OSS__8BIT 0x0 | ||
135 | #define BV_AIC_CCR_OSS__16BIT 0x1 | ||
136 | #define BV_AIC_CCR_OSS__18BIT 0x2 | ||
137 | #define BV_AIC_CCR_OSS__20BIT 0x3 | ||
138 | #define BV_AIC_CCR_OSS__24BIT 0x4 | ||
132 | #define BF_AIC_CCR_OSS(v) (((v) & 0x7) << 19) | 139 | #define BF_AIC_CCR_OSS(v) (((v) & 0x7) << 19) |
133 | #define BFM_AIC_CCR_OSS(v) BM_AIC_CCR_OSS | 140 | #define BFM_AIC_CCR_OSS(v) BM_AIC_CCR_OSS |
134 | #define BF_AIC_CCR_OSS_V(e) BF_AIC_CCR_OSS(BV_AIC_CCR_OSS__##e) | 141 | #define BF_AIC_CCR_OSS_V(e) BF_AIC_CCR_OSS(BV_AIC_CCR_OSS__##e) |
135 | #define BFM_AIC_CCR_OSS_V(v) BM_AIC_CCR_OSS | 142 | #define BFM_AIC_CCR_OSS_V(v) BM_AIC_CCR_OSS |
136 | #define BP_AIC_CCR_ISS 16 | 143 | #define BP_AIC_CCR_ISS 16 |
137 | #define BM_AIC_CCR_ISS 0x70000 | 144 | #define BM_AIC_CCR_ISS 0x70000 |
145 | #define BV_AIC_CCR_ISS__8BIT 0x0 | ||
146 | #define BV_AIC_CCR_ISS__16BIT 0x1 | ||
147 | #define BV_AIC_CCR_ISS__18BIT 0x2 | ||
148 | #define BV_AIC_CCR_ISS__20BIT 0x3 | ||
149 | #define BV_AIC_CCR_ISS__24BIT 0x4 | ||
138 | #define BF_AIC_CCR_ISS(v) (((v) & 0x7) << 16) | 150 | #define BF_AIC_CCR_ISS(v) (((v) & 0x7) << 16) |
139 | #define BFM_AIC_CCR_ISS(v) BM_AIC_CCR_ISS | 151 | #define BFM_AIC_CCR_ISS(v) BM_AIC_CCR_ISS |
140 | #define BF_AIC_CCR_ISS_V(e) BF_AIC_CCR_ISS(BV_AIC_CCR_ISS__##e) | 152 | #define BF_AIC_CCR_ISS_V(e) BF_AIC_CCR_ISS(BV_AIC_CCR_ISS__##e) |