]>
Commit | Line | Data |
---|---|---|
d0f8516d PF |
1 | /* |
2 | * Copyright (C) 2016 Freescale Semiconductor, Inc. | |
3 | * | |
4 | * SPDX-License-Identifier: GPL-2.0+ | |
5 | */ | |
6 | ||
7 | #include <common.h> | |
8 | #include <div64.h> | |
9 | #include <asm/io.h> | |
10 | #include <errno.h> | |
11 | #include <asm/arch/imx-regs.h> | |
12 | #include <asm/arch/pcc.h> | |
13 | #include <asm/arch/sys_proto.h> | |
14 | ||
15 | DECLARE_GLOBAL_DATA_PTR; | |
16 | ||
17 | scg_p scg1_regs = (scg_p)SCG1_RBASE; | |
18 | ||
19 | static u32 scg_src_get_rate(enum scg_clk clksrc) | |
20 | { | |
21 | u32 reg; | |
22 | ||
23 | switch (clksrc) { | |
24 | case SCG_SOSC_CLK: | |
25 | reg = readl(&scg1_regs->sosccsr); | |
26 | if (!(reg & SCG_SOSC_CSR_SOSCVLD_MASK)) | |
27 | return 0; | |
28 | ||
29 | return 24000000; | |
30 | case SCG_FIRC_CLK: | |
31 | reg = readl(&scg1_regs->firccsr); | |
32 | if (!(reg & SCG_FIRC_CSR_FIRCVLD_MASK)) | |
33 | return 0; | |
34 | ||
35 | return 48000000; | |
36 | case SCG_SIRC_CLK: | |
37 | reg = readl(&scg1_regs->sirccsr); | |
38 | if (!(reg & SCG_SIRC_CSR_SIRCVLD_MASK)) | |
39 | return 0; | |
40 | ||
41 | return 16000000; | |
42 | case SCG_ROSC_CLK: | |
43 | reg = readl(&scg1_regs->rtccsr); | |
44 | if (!(reg & SCG_ROSC_CSR_ROSCVLD_MASK)) | |
45 | return 0; | |
46 | ||
47 | return 32768; | |
48 | default: | |
49 | break; | |
50 | } | |
51 | ||
52 | return 0; | |
53 | } | |
54 | ||
55 | static u32 scg_sircdiv_get_rate(enum scg_clk clk) | |
56 | { | |
57 | u32 reg, val, rate; | |
58 | u32 shift, mask; | |
59 | ||
60 | switch (clk) { | |
61 | case SCG_SIRC_DIV1_CLK: | |
62 | mask = SCG_SIRCDIV_DIV1_MASK; | |
63 | shift = SCG_SIRCDIV_DIV1_SHIFT; | |
64 | break; | |
65 | case SCG_SIRC_DIV2_CLK: | |
66 | mask = SCG_SIRCDIV_DIV2_MASK; | |
67 | shift = SCG_SIRCDIV_DIV2_SHIFT; | |
68 | break; | |
69 | case SCG_SIRC_DIV3_CLK: | |
70 | mask = SCG_SIRCDIV_DIV3_MASK; | |
71 | shift = SCG_SIRCDIV_DIV3_SHIFT; | |
72 | break; | |
73 | default: | |
74 | return 0; | |
75 | } | |
76 | ||
77 | reg = readl(&scg1_regs->sirccsr); | |
78 | if (!(reg & SCG_SIRC_CSR_SIRCVLD_MASK)) | |
79 | return 0; | |
80 | ||
81 | reg = readl(&scg1_regs->sircdiv); | |
82 | val = (reg & mask) >> shift; | |
83 | ||
84 | if (!val) /*clock disabled*/ | |
85 | return 0; | |
86 | ||
87 | rate = scg_src_get_rate(SCG_SIRC_CLK); | |
88 | rate = rate / (1 << (val - 1)); | |
89 | ||
90 | return rate; | |
91 | } | |
92 | ||
93 | static u32 scg_fircdiv_get_rate(enum scg_clk clk) | |
94 | { | |
95 | u32 reg, val, rate; | |
96 | u32 shift, mask; | |
97 | ||
98 | switch (clk) { | |
99 | case SCG_FIRC_DIV1_CLK: | |
100 | mask = SCG_FIRCDIV_DIV1_MASK; | |
101 | shift = SCG_FIRCDIV_DIV1_SHIFT; | |
102 | break; | |
103 | case SCG_FIRC_DIV2_CLK: | |
104 | mask = SCG_FIRCDIV_DIV2_MASK; | |
105 | shift = SCG_FIRCDIV_DIV2_SHIFT; | |
106 | break; | |
107 | case SCG_FIRC_DIV3_CLK: | |
108 | mask = SCG_FIRCDIV_DIV3_MASK; | |
109 | shift = SCG_FIRCDIV_DIV3_SHIFT; | |
110 | break; | |
111 | default: | |
112 | return 0; | |
113 | } | |
114 | ||
115 | reg = readl(&scg1_regs->firccsr); | |
116 | if (!(reg & SCG_FIRC_CSR_FIRCVLD_MASK)) | |
117 | return 0; | |
118 | ||
119 | reg = readl(&scg1_regs->fircdiv); | |
120 | val = (reg & mask) >> shift; | |
121 | ||
122 | if (!val) /*clock disabled*/ | |
123 | return 0; | |
124 | ||
125 | rate = scg_src_get_rate(SCG_FIRC_CLK); | |
126 | rate = rate / (1 << (val - 1)); | |
127 | ||
128 | return rate; | |
129 | } | |
130 | ||
131 | static u32 scg_soscdiv_get_rate(enum scg_clk clk) | |
132 | { | |
133 | u32 reg, val, rate; | |
134 | u32 shift, mask; | |
135 | ||
136 | switch (clk) { | |
137 | case SCG_SOSC_DIV1_CLK: | |
138 | mask = SCG_SOSCDIV_DIV1_MASK; | |
139 | shift = SCG_SOSCDIV_DIV1_SHIFT; | |
140 | break; | |
141 | case SCG_SOSC_DIV2_CLK: | |
142 | mask = SCG_SOSCDIV_DIV2_MASK; | |
143 | shift = SCG_SOSCDIV_DIV2_SHIFT; | |
144 | break; | |
145 | case SCG_SOSC_DIV3_CLK: | |
146 | mask = SCG_SOSCDIV_DIV3_MASK; | |
147 | shift = SCG_SOSCDIV_DIV3_SHIFT; | |
148 | break; | |
149 | default: | |
150 | return 0; | |
151 | } | |
152 | ||
153 | reg = readl(&scg1_regs->sosccsr); | |
154 | if (!(reg & SCG_SOSC_CSR_SOSCVLD_MASK)) | |
155 | return 0; | |
156 | ||
157 | reg = readl(&scg1_regs->soscdiv); | |
158 | val = (reg & mask) >> shift; | |
159 | ||
160 | if (!val) /*clock disabled*/ | |
161 | return 0; | |
162 | ||
163 | rate = scg_src_get_rate(SCG_SOSC_CLK); | |
164 | rate = rate / (1 << (val - 1)); | |
165 | ||
166 | return rate; | |
167 | } | |
168 | ||
169 | static u32 scg_apll_pfd_get_rate(enum scg_clk clk) | |
170 | { | |
171 | u32 reg, val, rate; | |
172 | u32 shift, mask, gate, valid; | |
173 | ||
174 | switch (clk) { | |
175 | case SCG_APLL_PFD0_CLK: | |
176 | gate = SCG_PLL_PFD0_GATE_MASK; | |
177 | valid = SCG_PLL_PFD0_VALID_MASK; | |
178 | mask = SCG_PLL_PFD0_FRAC_MASK; | |
179 | shift = SCG_PLL_PFD0_FRAC_SHIFT; | |
180 | break; | |
181 | case SCG_APLL_PFD1_CLK: | |
182 | gate = SCG_PLL_PFD1_GATE_MASK; | |
183 | valid = SCG_PLL_PFD1_VALID_MASK; | |
184 | mask = SCG_PLL_PFD1_FRAC_MASK; | |
185 | shift = SCG_PLL_PFD1_FRAC_SHIFT; | |
186 | break; | |
187 | case SCG_APLL_PFD2_CLK: | |
188 | gate = SCG_PLL_PFD2_GATE_MASK; | |
189 | valid = SCG_PLL_PFD2_VALID_MASK; | |
190 | mask = SCG_PLL_PFD2_FRAC_MASK; | |
191 | shift = SCG_PLL_PFD2_FRAC_SHIFT; | |
192 | break; | |
193 | case SCG_APLL_PFD3_CLK: | |
194 | gate = SCG_PLL_PFD3_GATE_MASK; | |
195 | valid = SCG_PLL_PFD3_VALID_MASK; | |
196 | mask = SCG_PLL_PFD3_FRAC_MASK; | |
197 | shift = SCG_PLL_PFD3_FRAC_SHIFT; | |
198 | break; | |
199 | default: | |
200 | return 0; | |
201 | } | |
202 | ||
203 | reg = readl(&scg1_regs->apllpfd); | |
204 | if (reg & gate || !(reg & valid)) | |
205 | return 0; | |
206 | ||
207 | clk_debug("scg_apll_pfd_get_rate reg 0x%x\n", reg); | |
208 | ||
209 | val = (reg & mask) >> shift; | |
210 | rate = decode_pll(PLL_A7_APLL); | |
211 | ||
212 | rate = rate / val * 18; | |
213 | ||
214 | clk_debug("scg_apll_pfd_get_rate rate %u\n", rate); | |
215 | ||
216 | return rate; | |
217 | } | |
218 | ||
219 | static u32 scg_spll_pfd_get_rate(enum scg_clk clk) | |
220 | { | |
221 | u32 reg, val, rate; | |
222 | u32 shift, mask, gate, valid; | |
223 | ||
224 | switch (clk) { | |
225 | case SCG_SPLL_PFD0_CLK: | |
226 | gate = SCG_PLL_PFD0_GATE_MASK; | |
227 | valid = SCG_PLL_PFD0_VALID_MASK; | |
228 | mask = SCG_PLL_PFD0_FRAC_MASK; | |
229 | shift = SCG_PLL_PFD0_FRAC_SHIFT; | |
230 | break; | |
231 | case SCG_SPLL_PFD1_CLK: | |
232 | gate = SCG_PLL_PFD1_GATE_MASK; | |
233 | valid = SCG_PLL_PFD1_VALID_MASK; | |
234 | mask = SCG_PLL_PFD1_FRAC_MASK; | |
235 | shift = SCG_PLL_PFD1_FRAC_SHIFT; | |
236 | break; | |
237 | case SCG_SPLL_PFD2_CLK: | |
238 | gate = SCG_PLL_PFD2_GATE_MASK; | |
239 | valid = SCG_PLL_PFD2_VALID_MASK; | |
240 | mask = SCG_PLL_PFD2_FRAC_MASK; | |
241 | shift = SCG_PLL_PFD2_FRAC_SHIFT; | |
242 | break; | |
243 | case SCG_SPLL_PFD3_CLK: | |
244 | gate = SCG_PLL_PFD3_GATE_MASK; | |
245 | valid = SCG_PLL_PFD3_VALID_MASK; | |
246 | mask = SCG_PLL_PFD3_FRAC_MASK; | |
247 | shift = SCG_PLL_PFD3_FRAC_SHIFT; | |
248 | break; | |
249 | default: | |
250 | return 0; | |
251 | } | |
252 | ||
253 | reg = readl(&scg1_regs->spllpfd); | |
254 | if (reg & gate || !(reg & valid)) | |
255 | return 0; | |
256 | ||
257 | clk_debug("scg_spll_pfd_get_rate reg 0x%x\n", reg); | |
258 | ||
259 | val = (reg & mask) >> shift; | |
260 | rate = decode_pll(PLL_A7_SPLL); | |
261 | ||
262 | rate = rate / val * 18; | |
263 | ||
264 | clk_debug("scg_spll_pfd_get_rate rate %u\n", rate); | |
265 | ||
266 | return rate; | |
267 | } | |
268 | ||
269 | static u32 scg_apll_get_rate(void) | |
270 | { | |
271 | u32 reg, val, rate; | |
272 | ||
273 | reg = readl(&scg1_regs->apllcfg); | |
274 | val = (reg & SCG_PLL_CFG_PLLSEL_MASK) >> SCG_PLL_CFG_PLLSEL_SHIFT; | |
275 | ||
276 | if (!val) { | |
277 | /* APLL clock after two dividers */ | |
278 | rate = decode_pll(PLL_A7_APLL); | |
279 | ||
280 | val = (reg & SCG_PLL_CFG_POSTDIV1_MASK) >> | |
281 | SCG_PLL_CFG_POSTDIV1_SHIFT; | |
282 | rate = rate / (val + 1); | |
283 | ||
284 | val = (reg & SCG_PLL_CFG_POSTDIV2_MASK) >> | |
285 | SCG_PLL_CFG_POSTDIV2_SHIFT; | |
286 | rate = rate / (val + 1); | |
287 | } else { | |
288 | /* APLL PFD clock */ | |
289 | val = (reg & SCG_PLL_CFG_PFDSEL_MASK) >> | |
290 | SCG_PLL_CFG_PFDSEL_SHIFT; | |
291 | rate = scg_apll_pfd_get_rate(SCG_APLL_PFD0_CLK + val); | |
292 | } | |
293 | ||
294 | return rate; | |
295 | } | |
296 | ||
297 | static u32 scg_spll_get_rate(void) | |
298 | { | |
299 | u32 reg, val, rate; | |
300 | ||
301 | reg = readl(&scg1_regs->spllcfg); | |
302 | val = (reg & SCG_PLL_CFG_PLLSEL_MASK) >> SCG_PLL_CFG_PLLSEL_SHIFT; | |
303 | ||
304 | clk_debug("scg_spll_get_rate reg 0x%x\n", reg); | |
305 | ||
306 | if (!val) { | |
307 | /* APLL clock after two dividers */ | |
308 | rate = decode_pll(PLL_A7_SPLL); | |
309 | ||
310 | val = (reg & SCG_PLL_CFG_POSTDIV1_MASK) >> | |
311 | SCG_PLL_CFG_POSTDIV1_SHIFT; | |
312 | rate = rate / (val + 1); | |
313 | ||
314 | val = (reg & SCG_PLL_CFG_POSTDIV2_MASK) >> | |
315 | SCG_PLL_CFG_POSTDIV2_SHIFT; | |
316 | rate = rate / (val + 1); | |
317 | ||
318 | clk_debug("scg_spll_get_rate SPLL %u\n", rate); | |
319 | ||
320 | } else { | |
321 | /* APLL PFD clock */ | |
322 | val = (reg & SCG_PLL_CFG_PFDSEL_MASK) >> | |
323 | SCG_PLL_CFG_PFDSEL_SHIFT; | |
324 | rate = scg_spll_pfd_get_rate(SCG_SPLL_PFD0_CLK + val); | |
325 | ||
326 | clk_debug("scg_spll_get_rate PFD %u\n", rate); | |
327 | } | |
328 | ||
329 | return rate; | |
330 | } | |
331 | ||
332 | static u32 scg_ddr_get_rate(void) | |
333 | { | |
334 | u32 reg, val, rate, div; | |
335 | ||
336 | reg = readl(&scg1_regs->ddrccr); | |
337 | val = (reg & SCG_DDRCCR_DDRCS_MASK) >> SCG_DDRCCR_DDRCS_SHIFT; | |
338 | div = (reg & SCG_DDRCCR_DDRDIV_MASK) >> SCG_DDRCCR_DDRDIV_SHIFT; | |
339 | ||
340 | if (!div) | |
341 | return 0; | |
342 | ||
343 | if (!val) { | |
344 | reg = readl(&scg1_regs->apllcfg); | |
345 | val = (reg & SCG_PLL_CFG_PFDSEL_MASK) >> | |
346 | SCG_PLL_CFG_PFDSEL_SHIFT; | |
347 | rate = scg_apll_pfd_get_rate(SCG_APLL_PFD0_CLK + val); | |
348 | } else { | |
349 | rate = decode_pll(PLL_USB); | |
350 | } | |
351 | ||
352 | rate = rate / (1 << (div - 1)); | |
353 | return rate; | |
354 | } | |
355 | ||
356 | static u32 scg_nic_get_rate(enum scg_clk clk) | |
357 | { | |
358 | u32 reg, val, rate; | |
359 | u32 shift, mask; | |
360 | ||
361 | reg = readl(&scg1_regs->niccsr); | |
362 | val = (reg & SCG_NICCSR_NICCS_MASK) >> SCG_NICCSR_NICCS_SHIFT; | |
363 | ||
364 | clk_debug("scg_nic_get_rate niccsr 0x%x\n", reg); | |
365 | ||
366 | if (!val) | |
367 | rate = scg_src_get_rate(SCG_FIRC_CLK); | |
368 | else | |
369 | rate = scg_ddr_get_rate(); | |
370 | ||
371 | clk_debug("scg_nic_get_rate parent rate %u\n", rate); | |
372 | ||
373 | val = (reg & SCG_NICCSR_NIC0DIV_MASK) >> SCG_NICCSR_NIC0DIV_SHIFT; | |
374 | ||
375 | rate = rate / (val + 1); | |
376 | ||
377 | clk_debug("scg_nic_get_rate NIC0 rate %u\n", rate); | |
378 | ||
379 | switch (clk) { | |
380 | case SCG_NIC0_CLK: | |
381 | return rate; | |
382 | case SCG_GPU_CLK: | |
383 | mask = SCG_NICCSR_GPUDIV_MASK; | |
384 | shift = SCG_NICCSR_GPUDIV_SHIFT; | |
385 | break; | |
386 | case SCG_NIC1_EXT_CLK: | |
387 | case SCG_NIC1_BUS_CLK: | |
388 | case SCG_NIC1_CLK: | |
389 | mask = SCG_NICCSR_NIC1DIV_MASK; | |
390 | shift = SCG_NICCSR_NIC1DIV_SHIFT; | |
391 | break; | |
392 | default: | |
393 | return 0; | |
394 | } | |
395 | ||
396 | val = (reg & mask) >> shift; | |
397 | rate = rate / (val + 1); | |
398 | ||
399 | clk_debug("scg_nic_get_rate NIC1 rate %u\n", rate); | |
400 | ||
401 | switch (clk) { | |
402 | case SCG_GPU_CLK: | |
403 | case SCG_NIC1_CLK: | |
404 | return rate; | |
405 | case SCG_NIC1_EXT_CLK: | |
406 | mask = SCG_NICCSR_NIC1EXTDIV_MASK; | |
407 | shift = SCG_NICCSR_NIC1EXTDIV_SHIFT; | |
408 | break; | |
409 | case SCG_NIC1_BUS_CLK: | |
410 | mask = SCG_NICCSR_NIC1BUSDIV_MASK; | |
411 | shift = SCG_NICCSR_NIC1BUSDIV_SHIFT; | |
412 | break; | |
413 | default: | |
414 | return 0; | |
415 | } | |
416 | ||
417 | val = (reg & mask) >> shift; | |
418 | rate = rate / (val + 1); | |
419 | ||
420 | clk_debug("scg_nic_get_rate NIC1 bus rate %u\n", rate); | |
421 | return rate; | |
422 | } | |
423 | ||
424 | ||
425 | static enum scg_clk scg_scs_array[4] = { | |
426 | SCG_SOSC_CLK, SCG_SIRC_CLK, SCG_FIRC_CLK, SCG_ROSC_CLK, | |
427 | }; | |
428 | ||
429 | static u32 scg_sys_get_rate(enum scg_clk clk) | |
430 | { | |
431 | u32 reg, val, rate; | |
432 | ||
433 | if (clk != SCG_CORE_CLK && clk != SCG_BUS_CLK) | |
434 | return 0; | |
435 | ||
436 | reg = readl(&scg1_regs->csr); | |
437 | val = (reg & SCG_CCR_SCS_MASK) >> SCG_CCR_SCS_SHIFT; | |
438 | ||
439 | clk_debug("scg_sys_get_rate reg 0x%x\n", reg); | |
440 | ||
441 | switch (val) { | |
442 | case SCG_SCS_SYS_OSC: | |
443 | case SCG_SCS_SLOW_IRC: | |
444 | case SCG_SCS_FAST_IRC: | |
445 | case SCG_SCS_RTC_OSC: | |
446 | rate = scg_src_get_rate(scg_scs_array[val]); | |
447 | break; | |
448 | case 5: | |
449 | rate = scg_apll_get_rate(); | |
450 | break; | |
451 | case 6: | |
452 | rate = scg_spll_get_rate(); | |
453 | break; | |
454 | default: | |
455 | return 0; | |
456 | } | |
457 | ||
458 | clk_debug("scg_sys_get_rate parent rate %u\n", rate); | |
459 | ||
460 | val = (reg & SCG_CCR_DIVCORE_MASK) >> SCG_CCR_DIVCORE_SHIFT; | |
461 | ||
462 | rate = rate / (val + 1); | |
463 | ||
464 | if (clk == SCG_BUS_CLK) { | |
465 | val = (reg & SCG_CCR_DIVBUS_MASK) >> SCG_CCR_DIVBUS_SHIFT; | |
466 | rate = rate / (val + 1); | |
467 | } | |
468 | ||
469 | return rate; | |
470 | } | |
471 | ||
472 | u32 decode_pll(enum pll_clocks pll) | |
473 | { | |
474 | u32 reg, pre_div, infreq, mult; | |
475 | u32 num, denom; | |
476 | ||
477 | /* | |
478 | * Alought there are four choices for the bypass src, | |
479 | * we choose OSC_24M which is the default set in ROM. | |
480 | */ | |
481 | switch (pll) { | |
482 | case PLL_A7_SPLL: | |
483 | reg = readl(&scg1_regs->spllcsr); | |
484 | ||
485 | if (!(reg & SCG_SPLL_CSR_SPLLVLD_MASK)) | |
486 | return 0; | |
487 | ||
488 | reg = readl(&scg1_regs->spllcfg); | |
489 | ||
490 | pre_div = (reg & SCG_PLL_CFG_PREDIV_MASK) >> | |
491 | SCG_PLL_CFG_PREDIV_SHIFT; | |
492 | pre_div += 1; | |
493 | ||
494 | mult = (reg & SCG1_SPLL_CFG_MULT_MASK) >> | |
495 | SCG_PLL_CFG_MULT_SHIFT; | |
496 | ||
497 | infreq = (reg & SCG_PLL_CFG_CLKSRC_MASK) >> | |
498 | SCG_PLL_CFG_CLKSRC_SHIFT; | |
499 | if (!infreq) | |
500 | infreq = scg_src_get_rate(SCG_SOSC_CLK); | |
501 | else | |
502 | infreq = scg_src_get_rate(SCG_FIRC_CLK); | |
503 | ||
504 | num = readl(&scg1_regs->spllnum); | |
505 | denom = readl(&scg1_regs->splldenom); | |
506 | ||
2018ef86 YL |
507 | infreq = infreq / pre_div; |
508 | ||
509 | return infreq * mult + infreq * num / denom; | |
d0f8516d PF |
510 | |
511 | case PLL_A7_APLL: | |
512 | reg = readl(&scg1_regs->apllcsr); | |
513 | ||
514 | if (!(reg & SCG_APLL_CSR_APLLVLD_MASK)) | |
515 | return 0; | |
516 | ||
517 | reg = readl(&scg1_regs->apllcfg); | |
518 | ||
519 | pre_div = (reg & SCG_PLL_CFG_PREDIV_MASK) >> | |
520 | SCG_PLL_CFG_PREDIV_SHIFT; | |
521 | pre_div += 1; | |
522 | ||
523 | mult = (reg & SCG_APLL_CFG_MULT_MASK) >> | |
524 | SCG_PLL_CFG_MULT_SHIFT; | |
525 | ||
526 | infreq = (reg & SCG_PLL_CFG_CLKSRC_MASK) >> | |
527 | SCG_PLL_CFG_CLKSRC_SHIFT; | |
528 | if (!infreq) | |
529 | infreq = scg_src_get_rate(SCG_SOSC_CLK); | |
530 | else | |
531 | infreq = scg_src_get_rate(SCG_FIRC_CLK); | |
532 | ||
533 | num = readl(&scg1_regs->apllnum); | |
534 | denom = readl(&scg1_regs->aplldenom); | |
535 | ||
2018ef86 YL |
536 | infreq = infreq / pre_div; |
537 | ||
538 | return infreq * mult + infreq * num / denom; | |
d0f8516d PF |
539 | |
540 | case PLL_USB: | |
541 | reg = readl(&scg1_regs->upllcsr); | |
542 | ||
543 | if (!(reg & SCG_UPLL_CSR_UPLLVLD_MASK)) | |
544 | return 0; | |
545 | ||
546 | return 480000000u; | |
547 | ||
548 | case PLL_MIPI: | |
549 | return 480000000u; | |
550 | default: | |
551 | printf("Unsupported pll clocks %d\n", pll); | |
552 | break; | |
553 | } | |
554 | ||
555 | return 0; | |
556 | } | |
557 | ||
558 | u32 scg_clk_get_rate(enum scg_clk clk) | |
559 | { | |
560 | switch (clk) { | |
561 | case SCG_SIRC_DIV1_CLK: | |
562 | case SCG_SIRC_DIV2_CLK: | |
563 | case SCG_SIRC_DIV3_CLK: | |
564 | return scg_sircdiv_get_rate(clk); | |
565 | ||
566 | case SCG_FIRC_DIV1_CLK: | |
567 | case SCG_FIRC_DIV2_CLK: | |
568 | case SCG_FIRC_DIV3_CLK: | |
569 | return scg_fircdiv_get_rate(clk); | |
570 | ||
571 | case SCG_SOSC_DIV1_CLK: | |
572 | case SCG_SOSC_DIV2_CLK: | |
573 | case SCG_SOSC_DIV3_CLK: | |
574 | return scg_soscdiv_get_rate(clk); | |
575 | ||
576 | case SCG_CORE_CLK: | |
577 | case SCG_BUS_CLK: | |
578 | return scg_sys_get_rate(clk); | |
579 | ||
580 | case SCG_SPLL_PFD0_CLK: | |
581 | case SCG_SPLL_PFD1_CLK: | |
582 | case SCG_SPLL_PFD2_CLK: | |
583 | case SCG_SPLL_PFD3_CLK: | |
584 | return scg_spll_pfd_get_rate(clk); | |
585 | ||
586 | case SCG_APLL_PFD0_CLK: | |
587 | case SCG_APLL_PFD1_CLK: | |
588 | case SCG_APLL_PFD2_CLK: | |
589 | case SCG_APLL_PFD3_CLK: | |
590 | return scg_apll_pfd_get_rate(clk); | |
591 | ||
592 | case SCG_DDR_CLK: | |
593 | return scg_ddr_get_rate(); | |
594 | ||
595 | case SCG_NIC0_CLK: | |
596 | case SCG_GPU_CLK: | |
597 | case SCG_NIC1_CLK: | |
598 | case SCG_NIC1_BUS_CLK: | |
599 | case SCG_NIC1_EXT_CLK: | |
600 | return scg_nic_get_rate(clk); | |
601 | ||
602 | case USB_PLL_OUT: | |
603 | return decode_pll(PLL_USB); | |
604 | ||
605 | case MIPI_PLL_OUT: | |
606 | return decode_pll(PLL_MIPI); | |
607 | ||
608 | case SCG_SOSC_CLK: | |
609 | case SCG_FIRC_CLK: | |
610 | case SCG_SIRC_CLK: | |
611 | case SCG_ROSC_CLK: | |
612 | return scg_src_get_rate(clk); | |
613 | default: | |
614 | return 0; | |
615 | } | |
616 | } | |
617 | ||
618 | int scg_enable_pll_pfd(enum scg_clk clk, u32 frac) | |
619 | { | |
620 | u32 reg; | |
621 | u32 shift, mask, gate, valid; | |
622 | u32 addr; | |
623 | ||
624 | if (frac < 12 || frac > 35) | |
625 | return -EINVAL; | |
626 | ||
627 | switch (clk) { | |
628 | case SCG_SPLL_PFD0_CLK: | |
629 | case SCG_APLL_PFD0_CLK: | |
630 | gate = SCG_PLL_PFD0_GATE_MASK; | |
631 | valid = SCG_PLL_PFD0_VALID_MASK; | |
632 | mask = SCG_PLL_PFD0_FRAC_MASK; | |
633 | shift = SCG_PLL_PFD0_FRAC_SHIFT; | |
634 | ||
635 | if (clk == SCG_SPLL_PFD0_CLK) | |
636 | addr = (u32)(&scg1_regs->spllpfd); | |
637 | else | |
638 | addr = (u32)(&scg1_regs->apllpfd); | |
639 | break; | |
640 | case SCG_SPLL_PFD1_CLK: | |
641 | case SCG_APLL_PFD1_CLK: | |
642 | gate = SCG_PLL_PFD1_GATE_MASK; | |
643 | valid = SCG_PLL_PFD1_VALID_MASK; | |
644 | mask = SCG_PLL_PFD1_FRAC_MASK; | |
645 | shift = SCG_PLL_PFD1_FRAC_SHIFT; | |
646 | ||
647 | if (clk == SCG_SPLL_PFD1_CLK) | |
648 | addr = (u32)(&scg1_regs->spllpfd); | |
649 | else | |
650 | addr = (u32)(&scg1_regs->apllpfd); | |
651 | break; | |
652 | case SCG_SPLL_PFD2_CLK: | |
653 | case SCG_APLL_PFD2_CLK: | |
654 | gate = SCG_PLL_PFD2_GATE_MASK; | |
655 | valid = SCG_PLL_PFD2_VALID_MASK; | |
656 | mask = SCG_PLL_PFD2_FRAC_MASK; | |
657 | shift = SCG_PLL_PFD2_FRAC_SHIFT; | |
658 | ||
659 | if (clk == SCG_SPLL_PFD2_CLK) | |
660 | addr = (u32)(&scg1_regs->spllpfd); | |
661 | else | |
662 | addr = (u32)(&scg1_regs->apllpfd); | |
663 | break; | |
664 | case SCG_SPLL_PFD3_CLK: | |
665 | case SCG_APLL_PFD3_CLK: | |
666 | gate = SCG_PLL_PFD3_GATE_MASK; | |
667 | valid = SCG_PLL_PFD3_VALID_MASK; | |
668 | mask = SCG_PLL_PFD3_FRAC_MASK; | |
669 | shift = SCG_PLL_PFD3_FRAC_SHIFT; | |
670 | ||
671 | if (clk == SCG_SPLL_PFD3_CLK) | |
672 | addr = (u32)(&scg1_regs->spllpfd); | |
673 | else | |
674 | addr = (u32)(&scg1_regs->apllpfd); | |
675 | break; | |
676 | default: | |
677 | return -EINVAL; | |
678 | } | |
679 | ||
680 | /* Gate the PFD */ | |
681 | reg = readl(addr); | |
682 | reg |= gate; | |
683 | writel(reg, addr); | |
684 | ||
685 | /* Write Frac divider */ | |
686 | reg &= ~mask; | |
687 | reg |= (frac << shift) & mask; | |
688 | writel(reg, addr); | |
689 | ||
690 | /* | |
691 | * Un-gate the PFD | |
692 | * (Need un-gate before checking valid, not align with RM) | |
693 | */ | |
694 | reg &= ~gate; | |
695 | writel(reg, addr); | |
696 | ||
697 | /* Wait for PFD clock being valid */ | |
698 | do { | |
699 | reg = readl(addr); | |
700 | } while (!(reg & valid)); | |
701 | ||
702 | return 0; | |
703 | } | |
704 | ||
705 | #define SIM_MISC_CTRL0_USB_PLL_EN_MASK (0x1 << 2) | |
706 | int scg_enable_usb_pll(bool usb_control) | |
707 | { | |
708 | u32 sosc_rate; | |
709 | s32 timeout = 1000000; | |
710 | u32 reg; | |
711 | ||
712 | struct usbphy_regs *usbphy = | |
713 | (struct usbphy_regs *)USBPHY_RBASE; | |
714 | ||
715 | sosc_rate = scg_src_get_rate(SCG_SOSC_CLK); | |
716 | if (!sosc_rate) | |
717 | return -EPERM; | |
718 | ||
719 | reg = readl(SIM0_RBASE + 0x3C); | |
720 | if (usb_control) | |
721 | reg &= ~SIM_MISC_CTRL0_USB_PLL_EN_MASK; | |
722 | else | |
723 | reg |= SIM_MISC_CTRL0_USB_PLL_EN_MASK; | |
724 | writel(reg, SIM0_RBASE + 0x3C); | |
725 | ||
726 | if (!(readl(&usbphy->usb1_pll_480_ctrl) & PLL_USB_LOCK_MASK)) { | |
727 | writel(0x1c00000, &usbphy->usb1_pll_480_ctrl_clr); | |
728 | ||
729 | switch (sosc_rate) { | |
730 | case 24000000: | |
731 | writel(0xc00000, &usbphy->usb1_pll_480_ctrl_set); | |
732 | break; | |
733 | ||
734 | case 30000000: | |
735 | writel(0x800000, &usbphy->usb1_pll_480_ctrl_set); | |
736 | break; | |
737 | ||
738 | case 19200000: | |
739 | writel(0x1400000, &usbphy->usb1_pll_480_ctrl_set); | |
740 | break; | |
741 | ||
742 | default: | |
743 | writel(0xc00000, &usbphy->usb1_pll_480_ctrl_set); | |
744 | break; | |
745 | } | |
746 | ||
747 | /* Enable the regulator first */ | |
748 | writel(PLL_USB_REG_ENABLE_MASK, | |
749 | &usbphy->usb1_pll_480_ctrl_set); | |
750 | ||
751 | /* Wait at least 15us */ | |
752 | udelay(15); | |
753 | ||
754 | /* Enable the power */ | |
755 | writel(PLL_USB_PWR_MASK, &usbphy->usb1_pll_480_ctrl_set); | |
756 | ||
757 | /* Wait lock */ | |
758 | while (timeout--) { | |
759 | if (readl(&usbphy->usb1_pll_480_ctrl) & | |
760 | PLL_USB_LOCK_MASK) | |
761 | break; | |
762 | } | |
763 | ||
764 | if (timeout <= 0) { | |
765 | /* If timeout, we power down the pll */ | |
766 | writel(PLL_USB_PWR_MASK, | |
767 | &usbphy->usb1_pll_480_ctrl_clr); | |
768 | return -ETIME; | |
769 | } | |
770 | } | |
771 | ||
772 | /* Clear the bypass */ | |
773 | writel(PLL_USB_BYPASS_MASK, &usbphy->usb1_pll_480_ctrl_clr); | |
774 | ||
775 | /* Enable the PLL clock out to USB */ | |
776 | writel((PLL_USB_EN_USB_CLKS_MASK | PLL_USB_ENABLE_MASK), | |
777 | &usbphy->usb1_pll_480_ctrl_set); | |
778 | ||
779 | if (!usb_control) { | |
780 | while (timeout--) { | |
781 | if (readl(&scg1_regs->upllcsr) & | |
782 | SCG_UPLL_CSR_UPLLVLD_MASK) | |
783 | break; | |
784 | } | |
785 | ||
786 | if (timeout <= 0) { | |
787 | reg = readl(SIM0_RBASE + 0x3C); | |
788 | reg &= ~SIM_MISC_CTRL0_USB_PLL_EN_MASK; | |
789 | writel(reg, SIM0_RBASE + 0x3C); | |
790 | return -ETIME; | |
791 | } | |
792 | } | |
793 | ||
794 | return 0; | |
795 | } | |
796 | ||
797 | ||
798 | /* A7 domain system clock source is SPLL */ | |
799 | #define SCG1_RCCR_SCS_NUM ((SCG_SCS_SYS_PLL) << SCG_CCR_SCS_SHIFT) | |
800 | ||
801 | /* A7 Core clck = SPLL PFD0 / 1 = 500MHz / 1 = 500MHz */ | |
802 | #define SCG1_RCCR_DIVCORE_NUM ((0x0) << SCG_CCR_DIVCORE_SHIFT) | |
803 | #define SCG1_RCCR_CFG_MASK (SCG_CCR_SCS_MASK | SCG_CCR_DIVBUS_MASK) | |
804 | ||
805 | /* A7 Plat clck = A7 Core Clock / 2 = 250MHz / 1 = 250MHz */ | |
806 | #define SCG1_RCCR_DIVBUS_NUM ((0x1) << SCG_CCR_DIVBUS_SHIFT) | |
807 | #define SCG1_RCCR_CFG_NUM (SCG1_RCCR_SCS_NUM | SCG1_RCCR_DIVBUS_NUM) | |
808 | ||
809 | void scg_a7_rccr_init(void) | |
810 | { | |
811 | u32 rccr_reg_val = 0; | |
812 | ||
813 | rccr_reg_val = readl(&scg1_regs->rccr); | |
814 | ||
815 | rccr_reg_val &= (~SCG1_RCCR_CFG_MASK); | |
816 | rccr_reg_val |= (SCG1_RCCR_CFG_NUM); | |
817 | ||
818 | writel(rccr_reg_val, &scg1_regs->rccr); | |
819 | } | |
820 | ||
821 | /* POSTDIV2 = 1 */ | |
822 | #define SCG1_SPLL_CFG_POSTDIV2_NUM ((0x0) << SCG_PLL_CFG_POSTDIV2_SHIFT) | |
823 | /* POSTDIV1 = 1 */ | |
824 | #define SCG1_SPLL_CFG_POSTDIV1_NUM ((0x0) << SCG_PLL_CFG_POSTDIV1_SHIFT) | |
825 | ||
826 | /* MULT = 22 */ | |
827 | #define SCG1_SPLL_CFG_MULT_NUM ((22) << SCG_PLL_CFG_MULT_SHIFT) | |
828 | ||
829 | /* PFD0 output clock selected */ | |
830 | #define SCG1_SPLL_CFG_PFDSEL_NUM ((0) << SCG_PLL_CFG_PFDSEL_SHIFT) | |
831 | /* PREDIV = 1 */ | |
832 | #define SCG1_SPLL_CFG_PREDIV_NUM ((0x0) << SCG_PLL_CFG_PREDIV_SHIFT) | |
833 | /* SPLL output clocks (including PFD outputs) selected */ | |
834 | #define SCG1_SPLL_CFG_BYPASS_NUM ((0x0) << SCG_PLL_CFG_BYPASS_SHIFT) | |
835 | /* SPLL PFD output clock selected */ | |
836 | #define SCG1_SPLL_CFG_PLLSEL_NUM ((0x1) << SCG_PLL_CFG_PLLSEL_SHIFT) | |
837 | /* Clock source is System OSC */ | |
838 | #define SCG1_SPLL_CFG_CLKSRC_NUM ((0x0) << SCG_PLL_CFG_CLKSRC_SHIFT) | |
839 | #define SCG1_SPLL_CFG_NUM_24M_OSC (SCG1_SPLL_CFG_POSTDIV2_NUM | \ | |
840 | SCG1_SPLL_CFG_POSTDIV1_NUM | \ | |
841 | (22 << SCG_PLL_CFG_MULT_SHIFT) | \ | |
842 | SCG1_SPLL_CFG_PFDSEL_NUM | \ | |
843 | SCG1_SPLL_CFG_PREDIV_NUM | \ | |
844 | SCG1_SPLL_CFG_BYPASS_NUM | \ | |
845 | SCG1_SPLL_CFG_PLLSEL_NUM | \ | |
846 | SCG1_SPLL_CFG_CLKSRC_NUM) | |
847 | /*413Mhz = A7 SPLL(528MHz) * 18/23 */ | |
848 | #define SCG1_SPLL_PFD0_FRAC_NUM ((23) << SCG_PLL_PFD0_FRAC_SHIFT) | |
849 | ||
850 | void scg_a7_spll_init(void) | |
851 | { | |
852 | u32 val = 0; | |
853 | ||
854 | /* Disable A7 System PLL */ | |
855 | val = readl(&scg1_regs->spllcsr); | |
856 | val &= ~SCG_SPLL_CSR_SPLLEN_MASK; | |
857 | writel(val, &scg1_regs->spllcsr); | |
858 | ||
859 | /* | |
860 | * Per block guide, | |
861 | * "When changing PFD values, it is recommneded PFDx clock | |
862 | * gets gated first by writing a value of 1 to PFDx_CLKGATE register, | |
863 | * then program the new PFD value, then poll the PFDx_VALID | |
864 | * flag to set before writing a value of 0 to PFDx_CLKGATE | |
865 | * to ungate the PFDx clock and allow PFDx clock to run" | |
866 | */ | |
867 | ||
868 | /* Gate off A7 SPLL PFD0 ~ PDF4 */ | |
869 | val = readl(&scg1_regs->spllpfd); | |
870 | val |= (SCG_PLL_PFD3_GATE_MASK | | |
871 | SCG_PLL_PFD2_GATE_MASK | | |
872 | SCG_PLL_PFD1_GATE_MASK | | |
873 | SCG_PLL_PFD0_GATE_MASK); | |
874 | writel(val, &scg1_regs->spllpfd); | |
875 | ||
876 | /* ================ A7 SPLL Configuration Start ============== */ | |
877 | ||
878 | /* Configure A7 System PLL */ | |
879 | writel(SCG1_SPLL_CFG_NUM_24M_OSC, &scg1_regs->spllcfg); | |
880 | ||
881 | /* Enable A7 System PLL */ | |
882 | val = readl(&scg1_regs->spllcsr); | |
883 | val |= SCG_SPLL_CSR_SPLLEN_MASK; | |
884 | writel(val, &scg1_regs->spllcsr); | |
885 | ||
886 | /* Wait for A7 SPLL clock ready */ | |
887 | while (!(readl(&scg1_regs->spllcsr) & SCG_SPLL_CSR_SPLLVLD_MASK)) | |
888 | ; | |
889 | ||
890 | /* Configure A7 SPLL PFD0 */ | |
891 | val = readl(&scg1_regs->spllpfd); | |
892 | val &= ~SCG_PLL_PFD0_FRAC_MASK; | |
893 | val |= SCG1_SPLL_PFD0_FRAC_NUM; | |
894 | writel(val, &scg1_regs->spllpfd); | |
895 | ||
896 | /* Un-gate A7 SPLL PFD0 */ | |
897 | val = readl(&scg1_regs->spllpfd); | |
898 | val &= ~SCG_PLL_PFD0_GATE_MASK; | |
899 | writel(val, &scg1_regs->spllpfd); | |
900 | ||
901 | /* Wait for A7 SPLL PFD0 clock being valid */ | |
902 | while (!(readl(&scg1_regs->spllpfd) & SCG_PLL_PFD0_VALID_MASK)) | |
903 | ; | |
904 | ||
905 | /* ================ A7 SPLL Configuration End ============== */ | |
906 | } | |
907 | ||
908 | /* DDR clock source is APLL PFD0 (396MHz) */ | |
909 | #define SCG1_DDRCCR_DDRCS_NUM ((0x0) << SCG_DDRCCR_DDRCS_SHIFT) | |
910 | /* DDR clock = APLL PFD0 / 1 = 396MHz / 1 = 396MHz */ | |
911 | #define SCG1_DDRCCR_DDRDIV_NUM ((0x1) << SCG_DDRCCR_DDRDIV_SHIFT) | |
912 | /* DDR clock = APLL PFD0 / 2 = 396MHz / 2 = 198MHz */ | |
913 | #define SCG1_DDRCCR_DDRDIV_LF_NUM ((0x2) << SCG_DDRCCR_DDRDIV_SHIFT) | |
914 | #define SCG1_DDRCCR_CFG_NUM (SCG1_DDRCCR_DDRCS_NUM | \ | |
915 | SCG1_DDRCCR_DDRDIV_NUM) | |
916 | #define SCG1_DDRCCR_CFG_LF_NUM (SCG1_DDRCCR_DDRCS_NUM | \ | |
917 | SCG1_DDRCCR_DDRDIV_LF_NUM) | |
918 | void scg_a7_ddrclk_init(void) | |
919 | { | |
920 | writel(SCG1_DDRCCR_CFG_NUM, &scg1_regs->ddrccr); | |
921 | } | |
922 | ||
923 | /* SCG1(A7) APLLCFG configurations */ | |
924 | /* divide by 1 <<28 */ | |
925 | #define SCG1_APLL_CFG_POSTDIV2_NUM ((0x0) << SCG_PLL_CFG_POSTDIV2_SHIFT) | |
926 | /* divide by 1 <<24 */ | |
927 | #define SCG1_APLL_CFG_POSTDIV1_NUM ((0x0) << SCG_PLL_CFG_POSTDIV1_SHIFT) | |
928 | /* MULT is 22 <<16 */ | |
929 | #define SCG1_APLL_CFG_MULT_NUM ((22) << SCG_PLL_CFG_MULT_SHIFT) | |
930 | /* PFD0 output clock selected <<14 */ | |
931 | #define SCG1_APLL_CFG_PFDSEL_NUM ((0) << SCG_PLL_CFG_PFDSEL_SHIFT) | |
932 | /* PREDIV = 1 <<8 */ | |
933 | #define SCG1_APLL_CFG_PREDIV_NUM ((0x0) << SCG_PLL_CFG_PREDIV_SHIFT) | |
934 | /* APLL output clocks (including PFD outputs) selected <<2 */ | |
935 | #define SCG1_APLL_CFG_BYPASS_NUM ((0x0) << SCG_PLL_CFG_BYPASS_SHIFT) | |
936 | /* APLL PFD output clock selected <<1 */ | |
937 | #define SCG1_APLL_CFG_PLLSEL_NUM ((0x0) << SCG_PLL_CFG_PLLSEL_SHIFT) | |
938 | /* Clock source is System OSC <<0 */ | |
939 | #define SCG1_APLL_CFG_CLKSRC_NUM ((0x0) << SCG_PLL_CFG_CLKSRC_SHIFT) | |
940 | ||
941 | /* | |
942 | * A7 APLL = 24MHz / 1 * 22 / 1 / 1 = 528MHz, | |
943 | * system PLL is sourced from APLL, | |
944 | * APLL clock source is system OSC (24MHz) | |
945 | */ | |
946 | #define SCG1_APLL_CFG_NUM_24M_OSC (SCG1_APLL_CFG_POSTDIV2_NUM | \ | |
947 | SCG1_APLL_CFG_POSTDIV1_NUM | \ | |
948 | (22 << SCG_PLL_CFG_MULT_SHIFT) | \ | |
949 | SCG1_APLL_CFG_PFDSEL_NUM | \ | |
950 | SCG1_APLL_CFG_PREDIV_NUM | \ | |
951 | SCG1_APLL_CFG_BYPASS_NUM | \ | |
952 | SCG1_APLL_CFG_PLLSEL_NUM | \ | |
953 | SCG1_APLL_CFG_CLKSRC_NUM) | |
954 | ||
955 | /* PFD0 Freq = A7 APLL(528MHz) * 18 / 27 = 352MHz */ | |
956 | #define SCG1_APLL_PFD0_FRAC_NUM (27) | |
957 | ||
958 | ||
959 | void scg_a7_apll_init(void) | |
960 | { | |
961 | u32 val = 0; | |
962 | ||
963 | /* Disable A7 Auxiliary PLL */ | |
964 | val = readl(&scg1_regs->apllcsr); | |
965 | val &= ~SCG_APLL_CSR_APLLEN_MASK; | |
966 | writel(val, &scg1_regs->apllcsr); | |
967 | ||
968 | /* Gate off A7 APLL PFD0 ~ PDF4 */ | |
969 | val = readl(&scg1_regs->apllpfd); | |
970 | val |= 0x80808080; | |
971 | writel(val, &scg1_regs->apllpfd); | |
972 | ||
973 | /* ================ A7 APLL Configuration Start ============== */ | |
974 | /* Configure A7 Auxiliary PLL */ | |
975 | writel(SCG1_APLL_CFG_NUM_24M_OSC, &scg1_regs->apllcfg); | |
976 | ||
977 | /* Enable A7 Auxiliary PLL */ | |
978 | val = readl(&scg1_regs->apllcsr); | |
979 | val |= SCG_APLL_CSR_APLLEN_MASK; | |
980 | writel(val, &scg1_regs->apllcsr); | |
981 | ||
982 | /* Wait for A7 APLL clock ready */ | |
983 | while (!(readl(&scg1_regs->apllcsr) & SCG_APLL_CSR_APLLVLD_MASK)) | |
984 | ; | |
985 | ||
986 | /* Configure A7 APLL PFD0 */ | |
987 | val = readl(&scg1_regs->apllpfd); | |
988 | val &= ~SCG_PLL_PFD0_FRAC_MASK; | |
989 | val |= SCG1_APLL_PFD0_FRAC_NUM; | |
990 | writel(val, &scg1_regs->apllpfd); | |
991 | ||
992 | /* Un-gate A7 APLL PFD0 */ | |
993 | val = readl(&scg1_regs->apllpfd); | |
994 | val &= ~SCG_PLL_PFD0_GATE_MASK; | |
995 | writel(val, &scg1_regs->apllpfd); | |
996 | ||
997 | /* Wait for A7 APLL PFD0 clock being valid */ | |
998 | while (!(readl(&scg1_regs->apllpfd) & SCG_PLL_PFD0_VALID_MASK)) | |
999 | ; | |
1000 | } | |
1001 | ||
1002 | /* SCG1(A7) FIRC DIV configurations */ | |
1003 | /* Disable FIRC DIV3 */ | |
1004 | #define SCG1_FIRCDIV_DIV3_NUM ((0x0) << SCG_FIRCDIV_DIV3_SHIFT) | |
1005 | /* FIRC DIV2 = 48MHz / 1 = 48MHz */ | |
1006 | #define SCG1_FIRCDIV_DIV2_NUM ((0x1) << SCG_FIRCDIV_DIV2_SHIFT) | |
1007 | /* Disable FIRC DIV1 */ | |
1008 | #define SCG1_FIRCDIV_DIV1_NUM ((0x0) << SCG_FIRCDIV_DIV1_SHIFT) | |
1009 | ||
1010 | void scg_a7_firc_init(void) | |
1011 | { | |
1012 | /* Wait for FIRC clock ready */ | |
1013 | while (!(readl(&scg1_regs->firccsr) & SCG_FIRC_CSR_FIRCVLD_MASK)) | |
1014 | ; | |
1015 | ||
1016 | /* Configure A7 FIRC DIV1 ~ DIV3 */ | |
1017 | writel((SCG1_FIRCDIV_DIV3_NUM | | |
1018 | SCG1_FIRCDIV_DIV2_NUM | | |
1019 | SCG1_FIRCDIV_DIV1_NUM), &scg1_regs->fircdiv); | |
1020 | } | |
1021 | ||
1022 | /* SCG1(A7) NICCCR configurations */ | |
1023 | /* NIC clock source is DDR clock (396/198MHz) */ | |
1024 | #define SCG1_NICCCR_NICCS_NUM ((0x1) << SCG_NICCCR_NICCS_SHIFT) | |
1025 | ||
1026 | /* NIC0 clock = DDR Clock / 2 = 396MHz / 2 = 198MHz */ | |
1027 | #define SCG1_NICCCR_NIC0_DIV_NUM ((0x1) << SCG_NICCCR_NIC0_DIV_SHIFT) | |
1028 | /* NIC0 clock = DDR Clock / 1 = 198MHz / 1 = 198MHz */ | |
1029 | #define SCG1_NICCCR_NIC0_DIV_LF_NUM ((0x0) << SCG_NICCCR_NIC0_DIV_SHIFT) | |
1030 | /* NIC1 clock = NIC0 Clock / 1 = 198MHz / 2 = 198MHz */ | |
1031 | #define SCG1_NICCCR_NIC1_DIV_NUM ((0x0) << SCG_NICCCR_NIC1_DIV_SHIFT) | |
1032 | /* NIC1 bus clock = NIC1 Clock / 3 = 198MHz / 3 = 66MHz */ | |
1033 | #define SCG1_NICCCR_NIC1_DIVBUS_NUM ((0x2) << SCG_NICCCR_NIC1_DIVBUS_SHIFT) | |
1034 | #define SCG1_NICCCR_CFG_NUM (SCG1_NICCCR_NICCS_NUM | \ | |
1035 | SCG1_NICCCR_NIC0_DIV_NUM | \ | |
1036 | SCG1_NICCCR_NIC1_DIV_NUM | \ | |
1037 | SCG1_NICCCR_NIC1_DIVBUS_NUM) | |
1038 | ||
1039 | void scg_a7_nicclk_init(void) | |
1040 | { | |
1041 | writel(SCG1_NICCCR_CFG_NUM, &scg1_regs->nicccr); | |
1042 | } | |
1043 | ||
1044 | /* SCG1(A7) FIRC DIV configurations */ | |
1045 | /* Enable FIRC DIV3 */ | |
1046 | #define SCG1_SOSCDIV_DIV3_NUM ((0x1) << SCG_SOSCDIV_DIV3_SHIFT) | |
1047 | /* FIRC DIV2 = 48MHz / 1 = 48MHz */ | |
1048 | #define SCG1_SOSCDIV_DIV2_NUM ((0x1) << SCG_SOSCDIV_DIV2_SHIFT) | |
1049 | /* Enable FIRC DIV1 */ | |
1050 | #define SCG1_SOSCDIV_DIV1_NUM ((0x1) << SCG_SOSCDIV_DIV1_SHIFT) | |
1051 | ||
1052 | void scg_a7_soscdiv_init(void) | |
1053 | { | |
1054 | /* Wait for FIRC clock ready */ | |
1055 | while (!(readl(&scg1_regs->sosccsr) & SCG_SOSC_CSR_SOSCVLD_MASK)) | |
1056 | ; | |
1057 | ||
1058 | /* Configure A7 FIRC DIV1 ~ DIV3 */ | |
1059 | writel((SCG1_SOSCDIV_DIV3_NUM | SCG1_SOSCDIV_DIV2_NUM | | |
1060 | SCG1_SOSCDIV_DIV1_NUM), &scg1_regs->soscdiv); | |
1061 | } | |
1062 | ||
1063 | void scg_a7_sys_clk_sel(enum scg_sys_src clk) | |
1064 | { | |
1065 | u32 rccr_reg_val = 0; | |
1066 | ||
1067 | clk_debug("%s: system clock selected as %s\n", "[SCG]", | |
1068 | clk == SCG_SCS_SYS_OSC ? "SYS_OSC" : | |
1069 | clk == SCG_SCS_SLOW_IRC ? "SLOW_IRC" : | |
1070 | clk == SCG_SCS_FAST_IRC ? "FAST_IRC" : | |
1071 | clk == SCG_SCS_RTC_OSC ? "RTC_OSC" : | |
1072 | clk == SCG_SCS_AUX_PLL ? "AUX_PLL" : | |
1073 | clk == SCG_SCS_SYS_PLL ? "SYS_PLL" : | |
1074 | clk == SCG_SCS_USBPHY_PLL ? "USBPHY_PLL" : | |
1075 | "Invalid source" | |
1076 | ); | |
1077 | ||
1078 | rccr_reg_val = readl(&scg1_regs->rccr); | |
1079 | rccr_reg_val &= ~SCG_CCR_SCS_MASK; | |
1080 | rccr_reg_val |= (clk << SCG_CCR_SCS_SHIFT); | |
1081 | writel(rccr_reg_val, &scg1_regs->rccr); | |
1082 | } | |
1083 | ||
1084 | void scg_a7_info(void) | |
1085 | { | |
1086 | debug("SCG Version: 0x%x\n", readl(&scg1_regs->verid)); | |
1087 | debug("SCG Parameter: 0x%x\n", readl(&scg1_regs->param)); | |
1088 | debug("SCG RCCR Value: 0x%x\n", readl(&scg1_regs->rccr)); | |
1089 | debug("SCG Clock Status: 0x%x\n", readl(&scg1_regs->csr)); | |
1090 | } |