summaryrefslogtreecommitdiff
path: root/firmware/target/mips/ingenic_x1000/aic-x1000.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/mips/ingenic_x1000/aic-x1000.c')
-rw-r--r--firmware/target/mips/ingenic_x1000/aic-x1000.c132
1 files changed, 93 insertions, 39 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 */
34static unsigned cf_derive(unsigned m, unsigned n, unsigned* buf, unsigned cnt) 34static 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 */
57static void cf_expand(const unsigned* buf, unsigned count, 57static 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
75int aic_i2s_set_mclk(x1000_clk_t clksrc, unsigned fs, unsigned mult) 75static 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
129uint32_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
146int 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}