blob: 70c85ff434e2707f5d1ceab40c331d2c6e3284f3 [file] [log] [blame]
Patrick Georgi70517072020-05-10 18:47:05 +02001/* SPDX-License-Identifier: BSD-3-Clause */
Vadim Bendebury3cfb6a02015-02-11 15:13:04 -08002
Vadim Bendebury3cfb6a02015-02-11 15:13:04 -08003#include <stdint.h>
4#include <delay.h>
5#include <console/console.h>
6#include <soc/clock.h>
7#include <soc/lcc-reg.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +02008#include <device/mmio.h>
Vadim Bendebury3cfb6a02015-02-11 15:13:04 -08009
10typedef struct {
11 void *gcc_apcs_regs;
12 void *lcc_pll0_regs;
13 void *lcc_ahbix_regs;
14 void *lcc_mi2s_regs;
15 void *lcc_pll_regs;
16} Ipq806xLccClocks;
17
Stefan Reinauer6a001132017-07-13 02:20:27 +020018typedef struct __packed {
Vadim Bendebury3cfb6a02015-02-11 15:13:04 -080019 uint32_t apcs;
20} Ipq806xLccGccRegs;
21
Stefan Reinauer6a001132017-07-13 02:20:27 +020022typedef struct __packed {
Vadim Bendebury3cfb6a02015-02-11 15:13:04 -080023 uint32_t mode;
24 uint32_t l_val;
25 uint32_t m_val;
26 uint32_t n_val;
27 uint32_t UNUSED;
28 uint32_t config;
29 uint32_t status;
30} Ipq806xLccPll0Regs;
31
Stefan Reinauer6a001132017-07-13 02:20:27 +020032typedef struct __packed {
Vadim Bendebury3cfb6a02015-02-11 15:13:04 -080033 uint32_t ns;
34 uint32_t md;
35 uint32_t UNUSED;
36 uint32_t status;
37} Ipq806xLccAhbixRegs;
38
Stefan Reinauer6a001132017-07-13 02:20:27 +020039typedef struct __packed {
Vadim Bendebury3cfb6a02015-02-11 15:13:04 -080040 uint32_t ns;
41 uint32_t md;
42 uint32_t status;
43} Ipq806xLccMi2sRegs;
44
Stefan Reinauer6a001132017-07-13 02:20:27 +020045typedef struct __packed {
Vadim Bendebury3cfb6a02015-02-11 15:13:04 -080046 uint32_t pri;
47 uint32_t sec;
48} Ipq806xLccPllRegs;
49
50struct lcc_freq_tbl {
Martin Roth57e89092019-10-23 21:45:23 -060051 unsigned int freq;
52 unsigned int pd;
53 unsigned int m;
54 unsigned int n;
55 unsigned int d;
Vadim Bendebury3cfb6a02015-02-11 15:13:04 -080056};
57
58static const struct lcc_freq_tbl lcc_mi2s_freq_tbl[] = {
59 { 1024000, 4, 1, 96, 8 },
60 { 1411200, 4, 2, 139, 8 },
61 { 1536000, 4, 1, 64, 8 },
62 { 2048000, 4, 1, 48, 8 },
63 { 2116800, 4, 2, 93, 8 },
64 { 2304000, 4, 2, 85, 8 },
65 { 2822400, 4, 6, 209, 8 },
66 { 3072000, 4, 1, 32, 8 },
67 { 3175200, 4, 1, 31, 8 },
68 { 4096000, 4, 1, 24, 8 },
69 { 4233600, 4, 9, 209, 8 },
70 { 4608000, 4, 3, 64, 8 },
71 { 5644800, 4, 12, 209, 8 },
72 { 6144000, 4, 1, 16, 8 },
73 { 6350400, 4, 2, 31, 8 },
74 { 8192000, 4, 1, 12, 8 },
75 { 8467200, 4, 18, 209, 8 },
76 { 9216000, 4, 3, 32, 8 },
77 { 11289600, 4, 24, 209, 8 },
78 { 12288000, 4, 1, 8, 8 },
79 { 12700800, 4, 27, 209, 8 },
80 { 13824000, 4, 9, 64, 8 },
81 { 16384000, 4, 1, 6, 8 },
82 { 16934400, 4, 41, 238, 8 },
83 { 18432000, 4, 3, 16, 8 },
84 { 22579200, 2, 24, 209, 8 },
85 { 24576000, 4, 1, 4, 8 },
86 { 27648000, 4, 9, 32, 8 },
87 { 33868800, 4, 41, 119, 8 },
88 { 36864000, 4, 3, 8, 8 },
89 { 45158400, 1, 24, 209, 8 },
90 { 49152000, 4, 1, 2, 8 },
91 { 50803200, 1, 27, 209, 8 },
92 { }
93};
94
95static int lcc_init_enable_pll0(Ipq806xLccClocks *bus)
96{
97 Ipq806xLccGccRegs *gcc_regs = bus->gcc_apcs_regs;
98 Ipq806xLccPll0Regs *pll0_regs = bus->lcc_pll0_regs;
99 Ipq806xLccPllRegs *pll_regs = bus->lcc_pll_regs;
100 uint32_t regval;
101
102 regval = 0;
103 regval = 15 << LCC_PLL0_L_SHIFT & LCC_PLL0_L_MASK;
Julius Werner2f37bd62015-02-19 14:51:15 -0800104 write32(&pll0_regs->l_val, regval);
Vadim Bendebury3cfb6a02015-02-11 15:13:04 -0800105
106 regval = 0;
107 regval = 145 << LCC_PLL0_M_SHIFT & LCC_PLL0_M_MASK;
Julius Werner2f37bd62015-02-19 14:51:15 -0800108 write32(&pll0_regs->m_val, regval);
Vadim Bendebury3cfb6a02015-02-11 15:13:04 -0800109
110 regval = 0;
111 regval = 199 << LCC_PLL0_N_SHIFT & LCC_PLL0_N_MASK;
Julius Werner2f37bd62015-02-19 14:51:15 -0800112 write32(&pll0_regs->n_val, regval);
Vadim Bendebury3cfb6a02015-02-11 15:13:04 -0800113
114 regval = 0;
115 regval |= LCC_PLL0_CFG_LV_MAIN_ENABLE;
116 regval |= LCC_PLL0_CFG_FRAC_ENABLE;
Julius Werner2f37bd62015-02-19 14:51:15 -0800117 write32(&pll0_regs->config, regval);
Vadim Bendebury3cfb6a02015-02-11 15:13:04 -0800118
119 regval = 0;
120 regval |= LCC_PLL_PCLK_SRC_PRI;
Julius Werner2f37bd62015-02-19 14:51:15 -0800121 write32(&pll_regs->pri, regval);
Vadim Bendebury3cfb6a02015-02-11 15:13:04 -0800122
123 regval = 0;
124 regval |= 1 << LCC_PLL0_MODE_BIAS_CNT_SHIFT &
125 LCC_PLL0_MODE_BIAS_CNT_MASK;
126 regval |= 8 << LCC_PLL0_MODE_LOCK_CNT_SHIFT &
127 LCC_PLL0_MODE_LOCK_CNT_MASK;
Julius Werner2f37bd62015-02-19 14:51:15 -0800128 write32(&pll0_regs->mode, regval);
Vadim Bendebury3cfb6a02015-02-11 15:13:04 -0800129
Julius Werner2f37bd62015-02-19 14:51:15 -0800130 regval = read32(&gcc_regs->apcs);
Vadim Bendebury3cfb6a02015-02-11 15:13:04 -0800131 regval |= GCC_PLL_APCS_PLL4_ENABLE;
Julius Werner2f37bd62015-02-19 14:51:15 -0800132 write32(&gcc_regs->apcs, regval);
Vadim Bendebury3cfb6a02015-02-11 15:13:04 -0800133
Julius Werner2f37bd62015-02-19 14:51:15 -0800134 regval = read32(&pll0_regs->mode);
Vadim Bendebury3cfb6a02015-02-11 15:13:04 -0800135 regval |= LCC_PLL0_MODE_FSM_VOTE_ENABLE;
Julius Werner2f37bd62015-02-19 14:51:15 -0800136 write32(&pll0_regs->mode, regval);
Vadim Bendebury3cfb6a02015-02-11 15:13:04 -0800137
138 mdelay(1);
139
Julius Werner2f37bd62015-02-19 14:51:15 -0800140 regval = read32(&pll0_regs->status);
Vadim Bendebury3cfb6a02015-02-11 15:13:04 -0800141 if (regval & LCC_PLL0_STAT_ACTIVE_MASK)
142 return 0;
143
144 printk(BIOS_ERR, "%s: error enabling PLL4 clock\n", __func__);
145 return 1;
146}
147
148static int lcc_init_enable_ahbix(Ipq806xLccClocks *bus)
149{
150 Ipq806xLccAhbixRegs *ahbix_regs = bus->lcc_ahbix_regs;
151 uint32_t regval;
152
153 regval = 0;
154 regval |= 1 << LCC_AHBIX_MD_M_VAL_SHIFT & LCC_AHBIX_MD_M_VAL_MASK;
155 regval |= 252 << LCC_AHBIX_MD_NOT_2D_VAL_SHIFT &
156 LCC_AHBIX_MD_NOT_2D_VAL_MASK;
Julius Werner2f37bd62015-02-19 14:51:15 -0800157 write32(&ahbix_regs->md, regval);
Vadim Bendebury3cfb6a02015-02-11 15:13:04 -0800158
159 regval = 0;
160 regval |= 253 << LCC_AHBIX_NS_N_VAL_SHIFT & LCC_AHBIX_NS_N_VAL_MASK;
161 regval |= LCC_AHBIX_NS_CRC_ENABLE;
162 regval |= LCC_AHBIX_NS_GFM_SEL_MNC;
163 regval |= LCC_AHBIX_NS_MNC_CLK_ENABLE;
164 regval |= LCC_AHBIX_NS_MNC_ENABLE;
165 regval |= LCC_AHBIX_NS_MNC_MODE_DUAL;
166 regval |= LCC_AHBIX_NS_PREDIV_BYPASS;
167 regval |= LCC_AHBIX_NS_MN_SRC_LPA;
Julius Werner2f37bd62015-02-19 14:51:15 -0800168 write32(&ahbix_regs->ns, regval);
Vadim Bendebury3cfb6a02015-02-11 15:13:04 -0800169
170 mdelay(1);
171
Julius Werner2f37bd62015-02-19 14:51:15 -0800172 regval = read32(&ahbix_regs->status);
Vadim Bendebury3cfb6a02015-02-11 15:13:04 -0800173 if (regval & LCC_AHBIX_STAT_AIF_CLK_MASK)
174 return 0;
175
176 printk(BIOS_ERR, "%s: error enabling AHBIX clock\n", __func__);
177 return 1;
178}
179
Martin Roth57e89092019-10-23 21:45:23 -0600180static int lcc_init_mi2s(Ipq806xLccClocks *bus, unsigned int freq)
Vadim Bendebury3cfb6a02015-02-11 15:13:04 -0800181{
182 Ipq806xLccMi2sRegs *mi2s_regs = bus->lcc_mi2s_regs;
183 uint32_t regval;
184 uint8_t pd, m, n, d;
Martin Roth57e89092019-10-23 21:45:23 -0600185 unsigned int i;
Vadim Bendebury3cfb6a02015-02-11 15:13:04 -0800186
187 i = 0;
188 while (lcc_mi2s_freq_tbl[i].freq != 0) {
189 if (lcc_mi2s_freq_tbl[i].freq == freq)
190 break;
191 ++i;
192 }
193 if (lcc_mi2s_freq_tbl[i].freq == 0) {
194 printk(BIOS_ERR, "%s: invalid frequency given: %u\n",
195 __func__, freq);
196 return 1;
197 }
198
199 switch (lcc_mi2s_freq_tbl[i].pd) {
200 case 1:
201 pd = LCC_MI2S_NS_PREDIV_BYPASS;
202 break;
203 case 2:
204 pd = LCC_MI2S_NS_PREDIV_DIV2;
205 break;
206 case 4:
207 pd = LCC_MI2S_NS_PREDIV_DIV4;
208 break;
209 default:
210 printk(BIOS_ERR, "%s: invalid prediv found: %u\n", __func__,
211 lcc_mi2s_freq_tbl[i].pd);
212 return 1;
213 }
214
215 m = lcc_mi2s_freq_tbl[i].m;
216 n = ~(lcc_mi2s_freq_tbl[i].n - m);
217 d = ~(lcc_mi2s_freq_tbl[i].d * 2);
218
219 regval = 0;
220 regval |= m << LCC_MI2S_MD_M_VAL_SHIFT & LCC_MI2S_MD_M_VAL_MASK;
221 regval |= d << LCC_MI2S_MD_NOT_2D_VAL_SHIFT &
222 LCC_MI2S_MD_NOT_2D_VAL_MASK;
Julius Werner2f37bd62015-02-19 14:51:15 -0800223 write32(&mi2s_regs->md, regval);
Vadim Bendebury3cfb6a02015-02-11 15:13:04 -0800224
225 regval = 0;
226 regval |= n << LCC_MI2S_NS_N_VAL_SHIFT & LCC_MI2S_NS_N_VAL_MASK;
227 regval |= LCC_MI2S_NS_BIT_DIV_DIV4;
228 regval |= LCC_MI2S_NS_MNC_CLK_ENABLE;
229 regval |= LCC_MI2S_NS_MNC_ENABLE;
230 regval |= LCC_MI2S_NS_MNC_MODE_DUAL;
231 regval |= pd;
232 regval |= LCC_MI2S_NS_MN_SRC_LPA;
Julius Werner2f37bd62015-02-19 14:51:15 -0800233 write32(&mi2s_regs->ns, regval);
Vadim Bendebury3cfb6a02015-02-11 15:13:04 -0800234
235 return 0;
236}
237
238static int lcc_enable_mi2s(Ipq806xLccClocks *bus)
239{
240 Ipq806xLccMi2sRegs *mi2s_regs = bus->lcc_mi2s_regs;
241 uint32_t regval;
242
Julius Werner2f37bd62015-02-19 14:51:15 -0800243 regval = read32(&mi2s_regs->ns);
Vadim Bendebury3cfb6a02015-02-11 15:13:04 -0800244 regval |= LCC_MI2S_NS_OSR_CXC_ENABLE;
245 regval |= LCC_MI2S_NS_BIT_CXC_ENABLE;
Julius Werner2f37bd62015-02-19 14:51:15 -0800246 write32(&mi2s_regs->ns, regval);
Vadim Bendebury3cfb6a02015-02-11 15:13:04 -0800247
248 udelay(10);
249
Julius Werner2f37bd62015-02-19 14:51:15 -0800250 regval = read32(&mi2s_regs->status);
Vadim Bendebury3cfb6a02015-02-11 15:13:04 -0800251 if (regval & LCC_MI2S_STAT_OSR_CLK_MASK)
252 if (regval & LCC_MI2S_STAT_BIT_CLK_MASK)
253 return 0;
254
255 printk(BIOS_ERR, "%s: error enabling MI2S clocks: %u\n",
256 __func__, regval);
257 return 1;
258}
259
Martin Roth57e89092019-10-23 21:45:23 -0600260int audio_clock_config(unsigned int frequency)
Vadim Bendebury3cfb6a02015-02-11 15:13:04 -0800261{
Jacob Garber0f33d8c2019-07-22 16:20:36 -0600262 Ipq806xLccClocks bus = {
263 .gcc_apcs_regs = (void *)(MSM_GCC_BASE + GCC_PLL_APCS_REG),
264 .lcc_pll0_regs = (void *)(MSM_LPASS_LCC_BASE + LCC_PLL0_MODE_REG),
265 .lcc_ahbix_regs = (void *)(MSM_LPASS_LCC_BASE + LCC_AHBIX_NS_REG),
266 .lcc_mi2s_regs = (void *)(MSM_LPASS_LCC_BASE + LCC_MI2S_NS_REG),
267 .lcc_pll_regs = (void *)(MSM_LPASS_LCC_BASE + LCC_PLL_PCLK_REG),
268 };
Vadim Bendebury3cfb6a02015-02-11 15:13:04 -0800269
Jacob Garber0f33d8c2019-07-22 16:20:36 -0600270 if (lcc_init_enable_pll0(&bus))
Vadim Bendebury3cfb6a02015-02-11 15:13:04 -0800271 return 1;
Jacob Garber0f33d8c2019-07-22 16:20:36 -0600272 if (lcc_init_enable_ahbix(&bus))
Vadim Bendebury3cfb6a02015-02-11 15:13:04 -0800273 return 1;
Jacob Garber0f33d8c2019-07-22 16:20:36 -0600274 if (lcc_init_mi2s(&bus, frequency))
Vadim Bendebury3cfb6a02015-02-11 15:13:04 -0800275 return 1;
Jacob Garber0f33d8c2019-07-22 16:20:36 -0600276 if (lcc_enable_mi2s(&bus))
Vadim Bendebury3cfb6a02015-02-11 15:13:04 -0800277 return 1;
278
279 return 0;
280}