]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0 |
177ba1f9 LFT |
2 | /* |
3 | * Copyright (C) 2016-2017 Intel Corporation | |
177ba1f9 LFT |
4 | */ |
5 | ||
d678a59d | 6 | #include <common.h> |
177ba1f9 | 7 | #include <fdtdec.h> |
336d4615 | 8 | #include <malloc.h> |
177ba1f9 | 9 | #include <asm/io.h> |
21143ce1 | 10 | #include <dm.h> |
934aec71 MV |
11 | #include <clk.h> |
12 | #include <dm/device-internal.h> | |
177ba1f9 | 13 | #include <asm/arch/clock_manager.h> |
c05ed00a | 14 | #include <linux/delay.h> |
177ba1f9 | 15 | |
0b8f6378 | 16 | #ifdef CONFIG_SPL_BUILD |
480f7f9c | 17 | |
aea0e80a PA |
18 | void sdelay(unsigned long loops); |
19 | u32 wait_on_value(u32 read_bit_mask, u32 match_value, void *read_addr, | |
20 | u32 bound); | |
21 | ||
177ba1f9 LFT |
22 | static u32 eosc1_hz; |
23 | static u32 cb_intosc_hz; | |
24 | static u32 f2s_free_hz; | |
177ba1f9 LFT |
25 | |
26 | struct mainpll_cfg { | |
27 | u32 vco0_psrc; | |
28 | u32 vco1_denom; | |
29 | u32 vco1_numer; | |
30 | u32 mpuclk; | |
31 | u32 mpuclk_cnt; | |
32 | u32 mpuclk_src; | |
33 | u32 nocclk; | |
34 | u32 nocclk_cnt; | |
35 | u32 nocclk_src; | |
36 | u32 cntr2clk_cnt; | |
37 | u32 cntr3clk_cnt; | |
38 | u32 cntr4clk_cnt; | |
39 | u32 cntr5clk_cnt; | |
40 | u32 cntr6clk_cnt; | |
41 | u32 cntr7clk_cnt; | |
42 | u32 cntr7clk_src; | |
43 | u32 cntr8clk_cnt; | |
44 | u32 cntr9clk_cnt; | |
45 | u32 cntr9clk_src; | |
46 | u32 cntr15clk_cnt; | |
47 | u32 nocdiv_l4mainclk; | |
48 | u32 nocdiv_l4mpclk; | |
49 | u32 nocdiv_l4spclk; | |
50 | u32 nocdiv_csatclk; | |
51 | u32 nocdiv_cstraceclk; | |
52 | u32 nocdiv_cspdbclk; | |
53 | }; | |
54 | ||
55 | struct perpll_cfg { | |
56 | u32 vco0_psrc; | |
57 | u32 vco1_denom; | |
58 | u32 vco1_numer; | |
59 | u32 cntr2clk_cnt; | |
60 | u32 cntr2clk_src; | |
61 | u32 cntr3clk_cnt; | |
62 | u32 cntr3clk_src; | |
63 | u32 cntr4clk_cnt; | |
64 | u32 cntr4clk_src; | |
65 | u32 cntr5clk_cnt; | |
66 | u32 cntr5clk_src; | |
67 | u32 cntr6clk_cnt; | |
68 | u32 cntr6clk_src; | |
69 | u32 cntr7clk_cnt; | |
70 | u32 cntr8clk_cnt; | |
71 | u32 cntr8clk_src; | |
72 | u32 cntr9clk_cnt; | |
480f7f9c | 73 | u32 cntr9clk_src; |
177ba1f9 LFT |
74 | u32 emacctl_emac0sel; |
75 | u32 emacctl_emac1sel; | |
76 | u32 emacctl_emac2sel; | |
77 | u32 gpiodiv_gpiodbclk; | |
78 | }; | |
79 | ||
480f7f9c MV |
80 | struct strtou32 { |
81 | const char *str; | |
82 | const u32 val; | |
177ba1f9 LFT |
83 | }; |
84 | ||
480f7f9c MV |
85 | static const struct strtou32 mainpll_cfg_tab[] = { |
86 | { "vco0-psrc", offsetof(struct mainpll_cfg, vco0_psrc) }, | |
87 | { "vco1-denom", offsetof(struct mainpll_cfg, vco1_denom) }, | |
88 | { "vco1-numer", offsetof(struct mainpll_cfg, vco1_numer) }, | |
89 | { "mpuclk-cnt", offsetof(struct mainpll_cfg, mpuclk_cnt) }, | |
90 | { "mpuclk-src", offsetof(struct mainpll_cfg, mpuclk_src) }, | |
91 | { "nocclk-cnt", offsetof(struct mainpll_cfg, nocclk_cnt) }, | |
92 | { "nocclk-src", offsetof(struct mainpll_cfg, nocclk_src) }, | |
93 | { "cntr2clk-cnt", offsetof(struct mainpll_cfg, cntr2clk_cnt) }, | |
94 | { "cntr3clk-cnt", offsetof(struct mainpll_cfg, cntr3clk_cnt) }, | |
95 | { "cntr4clk-cnt", offsetof(struct mainpll_cfg, cntr4clk_cnt) }, | |
96 | { "cntr5clk-cnt", offsetof(struct mainpll_cfg, cntr5clk_cnt) }, | |
97 | { "cntr6clk-cnt", offsetof(struct mainpll_cfg, cntr6clk_cnt) }, | |
98 | { "cntr7clk-cnt", offsetof(struct mainpll_cfg, cntr7clk_cnt) }, | |
99 | { "cntr7clk-src", offsetof(struct mainpll_cfg, cntr7clk_src) }, | |
100 | { "cntr8clk-cnt", offsetof(struct mainpll_cfg, cntr8clk_cnt) }, | |
101 | { "cntr9clk-cnt", offsetof(struct mainpll_cfg, cntr9clk_cnt) }, | |
102 | { "cntr9clk-src", offsetof(struct mainpll_cfg, cntr9clk_src) }, | |
103 | { "cntr15clk-cnt", offsetof(struct mainpll_cfg, cntr15clk_cnt) }, | |
104 | { "nocdiv-l4mainclk", offsetof(struct mainpll_cfg, nocdiv_l4mainclk) }, | |
105 | { "nocdiv-l4mpclk", offsetof(struct mainpll_cfg, nocdiv_l4mpclk) }, | |
106 | { "nocdiv-l4spclk", offsetof(struct mainpll_cfg, nocdiv_l4spclk) }, | |
107 | { "nocdiv-csatclk", offsetof(struct mainpll_cfg, nocdiv_csatclk) }, | |
108 | { "nocdiv-cstraceclk", offsetof(struct mainpll_cfg, nocdiv_cstraceclk) }, | |
109 | { "nocdiv-cspdbgclk", offsetof(struct mainpll_cfg, nocdiv_cspdbclk) }, | |
110 | }; | |
111 | ||
112 | static const struct strtou32 perpll_cfg_tab[] = { | |
113 | { "vco0-psrc", offsetof(struct perpll_cfg, vco0_psrc) }, | |
114 | { "vco1-denom", offsetof(struct perpll_cfg, vco1_denom) }, | |
115 | { "vco1-numer", offsetof(struct perpll_cfg, vco1_numer) }, | |
116 | { "cntr2clk-cnt", offsetof(struct perpll_cfg, cntr2clk_cnt) }, | |
117 | { "cntr2clk-src", offsetof(struct perpll_cfg, cntr2clk_src) }, | |
118 | { "cntr3clk-cnt", offsetof(struct perpll_cfg, cntr3clk_cnt) }, | |
119 | { "cntr3clk-src", offsetof(struct perpll_cfg, cntr3clk_src) }, | |
120 | { "cntr4clk-cnt", offsetof(struct perpll_cfg, cntr4clk_cnt) }, | |
121 | { "cntr4clk-src", offsetof(struct perpll_cfg, cntr4clk_src) }, | |
122 | { "cntr5clk-cnt", offsetof(struct perpll_cfg, cntr5clk_cnt) }, | |
123 | { "cntr5clk-src", offsetof(struct perpll_cfg, cntr5clk_src) }, | |
124 | { "cntr6clk-cnt", offsetof(struct perpll_cfg, cntr6clk_cnt) }, | |
125 | { "cntr6clk-src", offsetof(struct perpll_cfg, cntr6clk_src) }, | |
126 | { "cntr7clk-cnt", offsetof(struct perpll_cfg, cntr7clk_cnt) }, | |
127 | { "cntr8clk-cnt", offsetof(struct perpll_cfg, cntr8clk_cnt) }, | |
128 | { "cntr8clk-src", offsetof(struct perpll_cfg, cntr8clk_src) }, | |
129 | { "cntr9clk-cnt", offsetof(struct perpll_cfg, cntr9clk_cnt) }, | |
130 | { "emacctl-emac0sel", offsetof(struct perpll_cfg, emacctl_emac0sel) }, | |
131 | { "emacctl-emac1sel", offsetof(struct perpll_cfg, emacctl_emac1sel) }, | |
132 | { "emacctl-emac2sel", offsetof(struct perpll_cfg, emacctl_emac2sel) }, | |
133 | { "gpiodiv-gpiodbclk", offsetof(struct perpll_cfg, gpiodiv_gpiodbclk) }, | |
134 | }; | |
135 | ||
136 | static const struct strtou32 alteragrp_cfg_tab[] = { | |
137 | { "nocclk", offsetof(struct mainpll_cfg, nocclk) }, | |
138 | { "mpuclk", offsetof(struct mainpll_cfg, mpuclk) }, | |
139 | }; | |
140 | ||
141 | struct strtopu32 { | |
142 | const char *str; | |
143 | u32 *p; | |
144 | }; | |
145 | ||
146 | const struct strtopu32 dt_to_val[] = { | |
934aec71 MV |
147 | { "altera_arria10_hps_eosc1", &eosc1_hz }, |
148 | { "altera_arria10_hps_cb_intosc_ls", &cb_intosc_hz }, | |
149 | { "altera_arria10_hps_f2h_free", &f2s_free_hz }, | |
480f7f9c | 150 | }; |
177ba1f9 | 151 | |
480f7f9c MV |
152 | static int of_to_struct(const void *blob, int node, const struct strtou32 *cfg_tab, |
153 | int cfg_tab_len, void *cfg) | |
177ba1f9 | 154 | { |
480f7f9c MV |
155 | int i; |
156 | u32 val; | |
157 | ||
158 | for (i = 0; i < cfg_tab_len; i++) { | |
159 | if (fdtdec_get_int_array(blob, node, cfg_tab[i].str, &val, 1)) { | |
160 | /* could not find required property */ | |
161 | return -EINVAL; | |
162 | } | |
163 | *(u32 *)(cfg + cfg_tab[i].val) = val; | |
177ba1f9 LFT |
164 | } |
165 | ||
166 | return 0; | |
167 | } | |
168 | ||
934aec71 | 169 | static int of_get_input_clks(const void *blob) |
177ba1f9 | 170 | { |
934aec71 MV |
171 | struct udevice *dev; |
172 | struct clk clk; | |
173 | int i, ret; | |
177ba1f9 | 174 | |
480f7f9c | 175 | for (i = 0; i < ARRAY_SIZE(dt_to_val); i++) { |
934aec71 | 176 | memset(&clk, 0, sizeof(clk)); |
480f7f9c | 177 | |
934aec71 MV |
178 | ret = uclass_get_device_by_name(UCLASS_CLK, dt_to_val[i].str, |
179 | &dev); | |
180 | if (ret) | |
181 | return ret; | |
480f7f9c | 182 | |
934aec71 MV |
183 | ret = clk_request(dev, &clk); |
184 | if (ret) | |
185 | return ret; | |
186 | ||
187 | *dt_to_val[i].p = clk_get_rate(&clk); | |
480f7f9c | 188 | } |
934aec71 MV |
189 | |
190 | return 0; | |
177ba1f9 LFT |
191 | } |
192 | ||
193 | static int of_get_clk_cfg(const void *blob, struct mainpll_cfg *main_cfg, | |
480f7f9c | 194 | struct perpll_cfg *per_cfg) |
177ba1f9 | 195 | { |
934aec71 | 196 | int ret, node, child, len; |
177ba1f9 LFT |
197 | const char *node_name; |
198 | ||
934aec71 MV |
199 | ret = of_get_input_clks(blob); |
200 | if (ret) | |
201 | return ret; | |
480f7f9c MV |
202 | |
203 | node = fdtdec_next_compatible(blob, 0, COMPAT_ALTERA_SOCFPGA_CLK_INIT); | |
204 | ||
177ba1f9 LFT |
205 | if (node < 0) |
206 | return -EINVAL; | |
207 | ||
208 | child = fdt_first_subnode(blob, node); | |
177ba1f9 | 209 | |
177ba1f9 LFT |
210 | if (child < 0) |
211 | return -EINVAL; | |
212 | ||
213 | node_name = fdt_get_name(blob, child, &len); | |
214 | ||
215 | while (node_name) { | |
480f7f9c MV |
216 | if (!strcmp(node_name, "mainpll")) { |
217 | if (of_to_struct(blob, child, mainpll_cfg_tab, | |
218 | ARRAY_SIZE(mainpll_cfg_tab), main_cfg)) | |
177ba1f9 | 219 | return -EINVAL; |
480f7f9c MV |
220 | } else if (!strcmp(node_name, "perpll")) { |
221 | if (of_to_struct(blob, child, perpll_cfg_tab, | |
222 | ARRAY_SIZE(perpll_cfg_tab), per_cfg)) | |
177ba1f9 | 223 | return -EINVAL; |
480f7f9c MV |
224 | } else if (!strcmp(node_name, "alteragrp")) { |
225 | if (of_to_struct(blob, child, alteragrp_cfg_tab, | |
226 | ARRAY_SIZE(alteragrp_cfg_tab), main_cfg)) | |
177ba1f9 | 227 | return -EINVAL; |
177ba1f9 LFT |
228 | } |
229 | child = fdt_next_subnode(blob, child); | |
230 | ||
231 | if (child < 0) | |
232 | break; | |
233 | ||
234 | node_name = fdt_get_name(blob, child, &len); | |
235 | } | |
236 | ||
237 | return 0; | |
238 | } | |
239 | ||
240 | /* calculate the intended main VCO frequency based on handoff */ | |
241 | static unsigned int cm_calc_handoff_main_vco_clk_hz | |
242 | (struct mainpll_cfg *main_cfg) | |
243 | { | |
244 | unsigned int clk_hz; | |
245 | ||
246 | /* Check main VCO clock source: eosc, intosc or f2s? */ | |
247 | switch (main_cfg->vco0_psrc) { | |
248 | case CLKMGR_MAINPLL_VCO0_PSRC_EOSC: | |
249 | clk_hz = eosc1_hz; | |
250 | break; | |
251 | case CLKMGR_MAINPLL_VCO0_PSRC_E_INTOSC: | |
252 | clk_hz = cb_intosc_hz; | |
253 | break; | |
254 | case CLKMGR_MAINPLL_VCO0_PSRC_F2S: | |
255 | clk_hz = f2s_free_hz; | |
256 | break; | |
257 | default: | |
258 | return 0; | |
259 | } | |
260 | ||
261 | /* calculate the VCO frequency */ | |
262 | clk_hz /= 1 + main_cfg->vco1_denom; | |
263 | clk_hz *= 1 + main_cfg->vco1_numer; | |
264 | ||
265 | return clk_hz; | |
266 | } | |
267 | ||
268 | /* calculate the intended periph VCO frequency based on handoff */ | |
269 | static unsigned int cm_calc_handoff_periph_vco_clk_hz( | |
270 | struct mainpll_cfg *main_cfg, struct perpll_cfg *per_cfg) | |
271 | { | |
272 | unsigned int clk_hz; | |
273 | ||
274 | /* Check periph VCO clock source: eosc, intosc, f2s or mainpll? */ | |
275 | switch (per_cfg->vco0_psrc) { | |
276 | case CLKMGR_PERPLL_VCO0_PSRC_EOSC: | |
277 | clk_hz = eosc1_hz; | |
278 | break; | |
279 | case CLKMGR_PERPLL_VCO0_PSRC_E_INTOSC: | |
280 | clk_hz = cb_intosc_hz; | |
281 | break; | |
282 | case CLKMGR_PERPLL_VCO0_PSRC_F2S: | |
283 | clk_hz = f2s_free_hz; | |
284 | break; | |
285 | case CLKMGR_PERPLL_VCO0_PSRC_MAIN: | |
286 | clk_hz = cm_calc_handoff_main_vco_clk_hz(main_cfg); | |
287 | clk_hz /= main_cfg->cntr15clk_cnt; | |
288 | break; | |
289 | default: | |
290 | return 0; | |
291 | } | |
292 | ||
293 | /* calculate the VCO frequency */ | |
294 | clk_hz /= 1 + per_cfg->vco1_denom; | |
295 | clk_hz *= 1 + per_cfg->vco1_numer; | |
296 | ||
297 | return clk_hz; | |
298 | } | |
299 | ||
300 | /* calculate the intended MPU clock frequency based on handoff */ | |
301 | static unsigned int cm_calc_handoff_mpu_clk_hz(struct mainpll_cfg *main_cfg, | |
302 | struct perpll_cfg *per_cfg) | |
303 | { | |
304 | unsigned int clk_hz; | |
305 | ||
306 | /* Check MPU clock source: main, periph, osc1, intosc or f2s? */ | |
307 | switch (main_cfg->mpuclk_src) { | |
308 | case CLKMGR_MAINPLL_MPUCLK_SRC_MAIN: | |
309 | clk_hz = cm_calc_handoff_main_vco_clk_hz(main_cfg); | |
310 | clk_hz /= (main_cfg->mpuclk & CLKMGR_MAINPLL_MPUCLK_CNT_MSK) | |
311 | + 1; | |
312 | break; | |
313 | case CLKMGR_MAINPLL_MPUCLK_SRC_PERI: | |
314 | clk_hz = cm_calc_handoff_periph_vco_clk_hz(main_cfg, per_cfg); | |
315 | clk_hz /= ((main_cfg->mpuclk >> | |
316 | CLKMGR_MAINPLL_MPUCLK_PERICNT_LSB) & | |
317 | CLKMGR_MAINPLL_MPUCLK_CNT_MSK) + 1; | |
318 | break; | |
319 | case CLKMGR_MAINPLL_MPUCLK_SRC_OSC1: | |
320 | clk_hz = eosc1_hz; | |
321 | break; | |
322 | case CLKMGR_MAINPLL_MPUCLK_SRC_INTOSC: | |
323 | clk_hz = cb_intosc_hz; | |
324 | break; | |
325 | case CLKMGR_MAINPLL_MPUCLK_SRC_FPGA: | |
326 | clk_hz = f2s_free_hz; | |
327 | break; | |
328 | default: | |
329 | return 0; | |
330 | } | |
331 | ||
332 | clk_hz /= main_cfg->mpuclk_cnt + 1; | |
333 | return clk_hz; | |
334 | } | |
335 | ||
336 | /* calculate the intended NOC clock frequency based on handoff */ | |
337 | static unsigned int cm_calc_handoff_noc_clk_hz(struct mainpll_cfg *main_cfg, | |
338 | struct perpll_cfg *per_cfg) | |
339 | { | |
340 | unsigned int clk_hz; | |
341 | ||
342 | /* Check MPU clock source: main, periph, osc1, intosc or f2s? */ | |
343 | switch (main_cfg->nocclk_src) { | |
344 | case CLKMGR_MAINPLL_NOCCLK_SRC_MAIN: | |
345 | clk_hz = cm_calc_handoff_main_vco_clk_hz(main_cfg); | |
346 | clk_hz /= (main_cfg->nocclk & CLKMGR_MAINPLL_NOCCLK_CNT_MSK) | |
347 | + 1; | |
348 | break; | |
349 | case CLKMGR_MAINPLL_NOCCLK_SRC_PERI: | |
350 | clk_hz = cm_calc_handoff_periph_vco_clk_hz(main_cfg, per_cfg); | |
351 | clk_hz /= ((main_cfg->nocclk >> | |
352 | CLKMGR_MAINPLL_NOCCLK_PERICNT_LSB) & | |
353 | CLKMGR_MAINPLL_NOCCLK_CNT_MSK) + 1; | |
354 | break; | |
355 | case CLKMGR_MAINPLL_NOCCLK_SRC_OSC1: | |
356 | clk_hz = eosc1_hz; | |
357 | break; | |
358 | case CLKMGR_MAINPLL_NOCCLK_SRC_INTOSC: | |
359 | clk_hz = cb_intosc_hz; | |
360 | break; | |
361 | case CLKMGR_MAINPLL_NOCCLK_SRC_FPGA: | |
362 | clk_hz = f2s_free_hz; | |
363 | break; | |
364 | default: | |
365 | return 0; | |
366 | } | |
367 | ||
368 | clk_hz /= main_cfg->nocclk_cnt + 1; | |
369 | return clk_hz; | |
370 | } | |
371 | ||
372 | /* return 1 if PLL ramp is required */ | |
373 | static int cm_is_pll_ramp_required(int main0periph1, | |
374 | struct mainpll_cfg *main_cfg, | |
375 | struct perpll_cfg *per_cfg) | |
376 | { | |
377 | /* Check for main PLL */ | |
378 | if (main0periph1 == 0) { | |
379 | /* | |
380 | * PLL ramp is not required if both MPU clock and NOC clock are | |
381 | * not sourced from main PLL | |
382 | */ | |
383 | if (main_cfg->mpuclk_src != CLKMGR_MAINPLL_MPUCLK_SRC_MAIN && | |
384 | main_cfg->nocclk_src != CLKMGR_MAINPLL_NOCCLK_SRC_MAIN) | |
385 | return 0; | |
386 | ||
387 | /* | |
388 | * PLL ramp is required if MPU clock is sourced from main PLL | |
389 | * and MPU clock is over 900MHz (as advised by HW team) | |
390 | */ | |
391 | if (main_cfg->mpuclk_src == CLKMGR_MAINPLL_MPUCLK_SRC_MAIN && | |
392 | (cm_calc_handoff_mpu_clk_hz(main_cfg, per_cfg) > | |
393 | CLKMGR_PLL_RAMP_MPUCLK_THRESHOLD_HZ)) | |
394 | return 1; | |
395 | ||
396 | /* | |
397 | * PLL ramp is required if NOC clock is sourced from main PLL | |
398 | * and NOC clock is over 300MHz (as advised by HW team) | |
399 | */ | |
400 | if (main_cfg->nocclk_src == CLKMGR_MAINPLL_NOCCLK_SRC_MAIN && | |
401 | (cm_calc_handoff_noc_clk_hz(main_cfg, per_cfg) > | |
402 | CLKMGR_PLL_RAMP_NOCCLK_THRESHOLD_HZ)) | |
403 | return 2; | |
404 | ||
405 | } else if (main0periph1 == 1) { | |
406 | /* | |
407 | * PLL ramp is not required if both MPU clock and NOC clock are | |
408 | * not sourced from periph PLL | |
409 | */ | |
410 | if (main_cfg->mpuclk_src != CLKMGR_MAINPLL_MPUCLK_SRC_PERI && | |
411 | main_cfg->nocclk_src != CLKMGR_MAINPLL_NOCCLK_SRC_PERI) | |
412 | return 0; | |
413 | ||
414 | /* | |
415 | * PLL ramp is required if MPU clock are source from periph PLL | |
416 | * and MPU clock is over 900MHz (as advised by HW team) | |
417 | */ | |
418 | if (main_cfg->mpuclk_src == CLKMGR_MAINPLL_MPUCLK_SRC_PERI && | |
419 | (cm_calc_handoff_mpu_clk_hz(main_cfg, per_cfg) > | |
420 | CLKMGR_PLL_RAMP_MPUCLK_THRESHOLD_HZ)) | |
421 | return 1; | |
422 | ||
423 | /* | |
424 | * PLL ramp is required if NOC clock are source from periph PLL | |
425 | * and NOC clock is over 300MHz (as advised by HW team) | |
426 | */ | |
427 | if (main_cfg->nocclk_src == CLKMGR_MAINPLL_NOCCLK_SRC_PERI && | |
428 | (cm_calc_handoff_noc_clk_hz(main_cfg, per_cfg) > | |
429 | CLKMGR_PLL_RAMP_NOCCLK_THRESHOLD_HZ)) | |
430 | return 2; | |
431 | } | |
432 | ||
433 | return 0; | |
434 | } | |
435 | ||
436 | static u32 cm_calculate_numer(struct mainpll_cfg *main_cfg, | |
437 | struct perpll_cfg *per_cfg, | |
438 | u32 safe_hz, u32 clk_hz) | |
439 | { | |
440 | u32 cnt; | |
441 | u32 clk; | |
442 | u32 shift; | |
443 | u32 mask; | |
444 | u32 denom; | |
445 | ||
446 | if (main_cfg->mpuclk_src == CLKMGR_MAINPLL_MPUCLK_SRC_MAIN) { | |
447 | cnt = main_cfg->mpuclk_cnt; | |
448 | clk = main_cfg->mpuclk; | |
449 | shift = 0; | |
450 | mask = CLKMGR_MAINPLL_MPUCLK_CNT_MSK; | |
451 | denom = main_cfg->vco1_denom; | |
452 | } else if (main_cfg->nocclk_src == CLKMGR_MAINPLL_NOCCLK_SRC_MAIN) { | |
453 | cnt = main_cfg->nocclk_cnt; | |
454 | clk = main_cfg->nocclk; | |
455 | shift = 0; | |
456 | mask = CLKMGR_MAINPLL_NOCCLK_CNT_MSK; | |
457 | denom = main_cfg->vco1_denom; | |
458 | } else if (main_cfg->mpuclk_src == CLKMGR_MAINPLL_MPUCLK_SRC_PERI) { | |
459 | cnt = main_cfg->mpuclk_cnt; | |
460 | clk = main_cfg->mpuclk; | |
461 | shift = CLKMGR_MAINPLL_MPUCLK_PERICNT_LSB; | |
462 | mask = CLKMGR_MAINPLL_MPUCLK_CNT_MSK; | |
463 | denom = per_cfg->vco1_denom; | |
464 | } else if (main_cfg->nocclk_src == CLKMGR_MAINPLL_NOCCLK_SRC_PERI) { | |
465 | cnt = main_cfg->nocclk_cnt; | |
466 | clk = main_cfg->nocclk; | |
467 | shift = CLKMGR_MAINPLL_NOCCLK_PERICNT_LSB; | |
468 | mask = CLKMGR_MAINPLL_NOCCLK_CNT_MSK; | |
469 | denom = per_cfg->vco1_denom; | |
470 | } else { | |
471 | return 0; | |
472 | } | |
473 | ||
474 | return (safe_hz / clk_hz) * (cnt + 1) * (((clk >> shift) & mask) + 1) * | |
475 | (1 + denom) - 1; | |
476 | } | |
477 | ||
478 | /* | |
479 | * Calculate the new PLL numerator which is based on existing DTS hand off and | |
480 | * intended safe frequency (safe_hz). Note that PLL ramp is only modifying the | |
481 | * numerator while maintaining denominator as denominator will influence the | |
482 | * jitter condition. Please refer A10 HPS TRM for the jitter guide. Note final | |
483 | * value for numerator is minus with 1 to cater our register value | |
484 | * representation. | |
485 | */ | |
486 | static unsigned int cm_calc_safe_pll_numer(int main0periph1, | |
487 | struct mainpll_cfg *main_cfg, | |
488 | struct perpll_cfg *per_cfg, | |
489 | unsigned int safe_hz) | |
490 | { | |
491 | unsigned int clk_hz = 0; | |
492 | ||
493 | /* Check for main PLL */ | |
494 | if (main0periph1 == 0) { | |
495 | /* Check main VCO clock source: eosc, intosc or f2s? */ | |
496 | switch (main_cfg->vco0_psrc) { | |
497 | case CLKMGR_MAINPLL_VCO0_PSRC_EOSC: | |
498 | clk_hz = eosc1_hz; | |
499 | break; | |
500 | case CLKMGR_MAINPLL_VCO0_PSRC_E_INTOSC: | |
501 | clk_hz = cb_intosc_hz; | |
502 | break; | |
503 | case CLKMGR_MAINPLL_VCO0_PSRC_F2S: | |
504 | clk_hz = f2s_free_hz; | |
505 | break; | |
506 | default: | |
507 | return 0; | |
508 | } | |
509 | } else if (main0periph1 == 1) { | |
510 | /* Check periph VCO clock source: eosc, intosc, f2s, mainpll */ | |
511 | switch (per_cfg->vco0_psrc) { | |
512 | case CLKMGR_PERPLL_VCO0_PSRC_EOSC: | |
513 | clk_hz = eosc1_hz; | |
514 | break; | |
515 | case CLKMGR_PERPLL_VCO0_PSRC_E_INTOSC: | |
516 | clk_hz = cb_intosc_hz; | |
517 | break; | |
518 | case CLKMGR_PERPLL_VCO0_PSRC_F2S: | |
519 | clk_hz = f2s_free_hz; | |
520 | break; | |
521 | case CLKMGR_PERPLL_VCO0_PSRC_MAIN: | |
522 | clk_hz = cm_calc_handoff_main_vco_clk_hz(main_cfg); | |
523 | clk_hz /= main_cfg->cntr15clk_cnt; | |
524 | break; | |
525 | default: | |
526 | return 0; | |
527 | } | |
528 | } else { | |
529 | return 0; | |
530 | } | |
531 | ||
532 | return cm_calculate_numer(main_cfg, per_cfg, safe_hz, clk_hz); | |
533 | } | |
534 | ||
535 | /* ramping the main PLL to final value */ | |
536 | static void cm_pll_ramp_main(struct mainpll_cfg *main_cfg, | |
537 | struct perpll_cfg *per_cfg, | |
538 | unsigned int pll_ramp_main_hz) | |
539 | { | |
540 | unsigned int clk_hz = 0, clk_incr_hz = 0, clk_final_hz = 0; | |
541 | ||
542 | /* find out the increment value */ | |
543 | if (main_cfg->mpuclk_src == CLKMGR_MAINPLL_MPUCLK_SRC_MAIN) { | |
544 | clk_incr_hz = CLKMGR_PLL_RAMP_MPUCLK_INCREMENT_HZ; | |
545 | clk_final_hz = cm_calc_handoff_mpu_clk_hz(main_cfg, per_cfg); | |
546 | } else if (main_cfg->nocclk_src == CLKMGR_MAINPLL_NOCCLK_SRC_MAIN) { | |
547 | clk_incr_hz = CLKMGR_PLL_RAMP_NOCCLK_INCREMENT_HZ; | |
548 | clk_final_hz = cm_calc_handoff_noc_clk_hz(main_cfg, per_cfg); | |
549 | } | |
550 | ||
551 | /* execute the ramping here */ | |
552 | for (clk_hz = pll_ramp_main_hz + clk_incr_hz; | |
553 | clk_hz < clk_final_hz; clk_hz += clk_incr_hz) { | |
554 | writel((main_cfg->vco1_denom << | |
555 | CLKMGR_MAINPLL_VCO1_DENOM_LSB) | | |
556 | cm_calc_safe_pll_numer(0, main_cfg, per_cfg, clk_hz), | |
94172c79 | 557 | socfpga_get_clkmgr_addr() + CLKMGR_A10_MAINPLL_VCO1); |
aea0e80a | 558 | sdelay(1000000); /* 1ms */ |
177ba1f9 LFT |
559 | cm_wait_for_lock(LOCKED_MASK); |
560 | } | |
561 | writel((main_cfg->vco1_denom << CLKMGR_MAINPLL_VCO1_DENOM_LSB) | | |
94172c79 LFT |
562 | main_cfg->vco1_numer, |
563 | socfpga_get_clkmgr_addr() + CLKMGR_A10_MAINPLL_VCO1); | |
aea0e80a | 564 | sdelay(1000000); /* 1ms */ |
177ba1f9 LFT |
565 | cm_wait_for_lock(LOCKED_MASK); |
566 | } | |
567 | ||
568 | /* ramping the periph PLL to final value */ | |
569 | static void cm_pll_ramp_periph(struct mainpll_cfg *main_cfg, | |
570 | struct perpll_cfg *per_cfg, | |
571 | unsigned int pll_ramp_periph_hz) | |
572 | { | |
573 | unsigned int clk_hz = 0, clk_incr_hz = 0, clk_final_hz = 0; | |
574 | ||
575 | /* find out the increment value */ | |
576 | if (main_cfg->mpuclk_src == CLKMGR_MAINPLL_MPUCLK_SRC_PERI) { | |
577 | clk_incr_hz = CLKMGR_PLL_RAMP_MPUCLK_INCREMENT_HZ; | |
578 | clk_final_hz = cm_calc_handoff_mpu_clk_hz(main_cfg, per_cfg); | |
579 | } else if (main_cfg->nocclk_src == CLKMGR_MAINPLL_NOCCLK_SRC_PERI) { | |
580 | clk_incr_hz = CLKMGR_PLL_RAMP_NOCCLK_INCREMENT_HZ; | |
581 | clk_final_hz = cm_calc_handoff_noc_clk_hz(main_cfg, per_cfg); | |
582 | } | |
583 | /* execute the ramping here */ | |
584 | for (clk_hz = pll_ramp_periph_hz + clk_incr_hz; | |
585 | clk_hz < clk_final_hz; clk_hz += clk_incr_hz) { | |
94172c79 LFT |
586 | writel((per_cfg->vco1_denom << |
587 | CLKMGR_PERPLL_VCO1_DENOM_LSB) | | |
588 | cm_calc_safe_pll_numer(1, main_cfg, per_cfg, | |
589 | clk_hz), | |
590 | socfpga_get_clkmgr_addr() + | |
591 | CLKMGR_A10_PERPLL_VCO1); | |
aea0e80a | 592 | sdelay(1000000); /* 1ms */ |
177ba1f9 LFT |
593 | cm_wait_for_lock(LOCKED_MASK); |
594 | } | |
595 | writel((per_cfg->vco1_denom << CLKMGR_PERPLL_VCO1_DENOM_LSB) | | |
94172c79 LFT |
596 | per_cfg->vco1_numer, |
597 | socfpga_get_clkmgr_addr() + CLKMGR_A10_PERPLL_VCO1); | |
aea0e80a | 598 | sdelay(1000000); /* 1ms */ |
177ba1f9 LFT |
599 | cm_wait_for_lock(LOCKED_MASK); |
600 | } | |
601 | ||
aea0e80a PA |
602 | /* function to poll in the fsm busy bit */ |
603 | static int cm_busy_wait_for_fsm(void) | |
604 | { | |
605 | void *reg = (void *)(socfpga_get_clkmgr_addr() + CLKMGR_STAT); | |
606 | ||
607 | /* 20s timeout */ | |
608 | return wait_on_value(CLKMGR_STAT_BUSY, 0, reg, 100000000); | |
609 | } | |
610 | ||
177ba1f9 LFT |
611 | /* |
612 | * Setup clocks while making no assumptions of the | |
613 | * previous state of the clocks. | |
614 | * | |
615 | * Start by being paranoid and gate all sw managed clocks | |
616 | * | |
617 | * Put all plls in bypass | |
618 | * | |
619 | * Put all plls VCO registers back to reset value (bgpwr dwn). | |
620 | * | |
621 | * Put peripheral and main pll src to reset value to avoid glitch. | |
622 | * | |
623 | * Delay 5 us. | |
624 | * | |
625 | * Deassert bg pwr dn and set numerator and denominator | |
626 | * | |
627 | * Start 7 us timer. | |
628 | * | |
629 | * set internal dividers | |
630 | * | |
631 | * Wait for 7 us timer. | |
632 | * | |
633 | * Enable plls | |
634 | * | |
635 | * Set external dividers while plls are locking | |
636 | * | |
637 | * Wait for pll lock | |
638 | * | |
639 | * Assert/deassert outreset all. | |
640 | * | |
641 | * Take all pll's out of bypass | |
642 | * | |
643 | * Clear safe mode | |
644 | * | |
645 | * set source main and peripheral clocks | |
646 | * | |
647 | * Ungate clocks | |
648 | */ | |
649 | ||
650 | static int cm_full_cfg(struct mainpll_cfg *main_cfg, struct perpll_cfg *per_cfg) | |
651 | { | |
652 | unsigned int pll_ramp_main_hz = 0, pll_ramp_periph_hz = 0, | |
653 | ramp_required; | |
654 | ||
655 | /* gate off all mainpll clock excpet HW managed clock */ | |
656 | writel(CLKMGR_MAINPLL_EN_S2FUSER0CLKEN_SET_MSK | | |
657 | CLKMGR_MAINPLL_EN_HMCPLLREFCLKEN_SET_MSK, | |
94172c79 | 658 | socfpga_get_clkmgr_addr() + CLKMGR_A10_MAINPLL_ENR); |
177ba1f9 LFT |
659 | |
660 | /* now we can gate off the rest of the peripheral clocks */ | |
94172c79 | 661 | writel(0, socfpga_get_clkmgr_addr() + CLKMGR_A10_PERPLL_EN); |
177ba1f9 LFT |
662 | |
663 | /* Put all plls in external bypass */ | |
664 | writel(CLKMGR_MAINPLL_BYPASS_RESET, | |
94172c79 | 665 | socfpga_get_clkmgr_addr() + CLKMGR_A10_MAINPLL_BYPASSS); |
177ba1f9 | 666 | writel(CLKMGR_PERPLL_BYPASS_RESET, |
94172c79 | 667 | socfpga_get_clkmgr_addr() + CLKMGR_A10_PERPLL_BYPASSS); |
177ba1f9 LFT |
668 | |
669 | /* | |
670 | * Put all plls VCO registers back to reset value. | |
671 | * Some code might have messed with them. At same time set the | |
672 | * desired clock source | |
673 | */ | |
674 | writel(CLKMGR_MAINPLL_VCO0_RESET | | |
675 | CLKMGR_MAINPLL_VCO0_REGEXTSEL_SET_MSK | | |
676 | (main_cfg->vco0_psrc << CLKMGR_MAINPLL_VCO0_PSRC_LSB), | |
94172c79 | 677 | socfpga_get_clkmgr_addr() + CLKMGR_A10_MAINPLL_VCO0); |
177ba1f9 LFT |
678 | |
679 | writel(CLKMGR_PERPLL_VCO0_RESET | | |
680 | CLKMGR_PERPLL_VCO0_REGEXTSEL_SET_MSK | | |
681 | (per_cfg->vco0_psrc << CLKMGR_PERPLL_VCO0_PSRC_LSB), | |
94172c79 | 682 | socfpga_get_clkmgr_addr() + CLKMGR_A10_PERPLL_VCO0); |
177ba1f9 | 683 | |
94172c79 LFT |
684 | writel(CLKMGR_MAINPLL_VCO1_RESET, |
685 | socfpga_get_clkmgr_addr() + CLKMGR_A10_MAINPLL_VCO1); | |
686 | writel(CLKMGR_PERPLL_VCO1_RESET, | |
687 | socfpga_get_clkmgr_addr() + CLKMGR_A10_PERPLL_VCO1); | |
177ba1f9 LFT |
688 | |
689 | /* clear the interrupt register status register */ | |
690 | writel(CLKMGR_CLKMGR_INTR_MAINPLLLOST_SET_MSK | | |
691 | CLKMGR_CLKMGR_INTR_PERPLLLOST_SET_MSK | | |
692 | CLKMGR_CLKMGR_INTR_MAINPLLRFSLIP_SET_MSK | | |
693 | CLKMGR_CLKMGR_INTR_PERPLLRFSLIP_SET_MSK | | |
694 | CLKMGR_CLKMGR_INTR_MAINPLLFBSLIP_SET_MSK | | |
695 | CLKMGR_CLKMGR_INTR_PERPLLFBSLIP_SET_MSK | | |
696 | CLKMGR_CLKMGR_INTR_MAINPLLACHIEVED_SET_MSK | | |
697 | CLKMGR_CLKMGR_INTR_PERPLLACHIEVED_SET_MSK, | |
94172c79 | 698 | socfpga_get_clkmgr_addr() + CLKMGR_A10_INTR); |
177ba1f9 LFT |
699 | |
700 | /* Program VCO Numerator and Denominator for main PLL */ | |
701 | ramp_required = cm_is_pll_ramp_required(0, main_cfg, per_cfg); | |
702 | if (ramp_required) { | |
703 | /* set main PLL to safe starting threshold frequency */ | |
704 | if (ramp_required == 1) | |
705 | pll_ramp_main_hz = CLKMGR_PLL_RAMP_MPUCLK_THRESHOLD_HZ; | |
706 | else if (ramp_required == 2) | |
707 | pll_ramp_main_hz = CLKMGR_PLL_RAMP_NOCCLK_THRESHOLD_HZ; | |
708 | ||
94172c79 LFT |
709 | writel((main_cfg->vco1_denom << |
710 | CLKMGR_MAINPLL_VCO1_DENOM_LSB) | | |
177ba1f9 LFT |
711 | cm_calc_safe_pll_numer(0, main_cfg, per_cfg, |
712 | pll_ramp_main_hz), | |
94172c79 | 713 | socfpga_get_clkmgr_addr() + CLKMGR_A10_MAINPLL_VCO1); |
177ba1f9 | 714 | } else |
94172c79 LFT |
715 | writel((main_cfg->vco1_denom << |
716 | CLKMGR_MAINPLL_VCO1_DENOM_LSB) | | |
717 | main_cfg->vco1_numer, | |
718 | socfpga_get_clkmgr_addr() + CLKMGR_A10_MAINPLL_VCO1); | |
177ba1f9 LFT |
719 | |
720 | /* Program VCO Numerator and Denominator for periph PLL */ | |
721 | ramp_required = cm_is_pll_ramp_required(1, main_cfg, per_cfg); | |
722 | if (ramp_required) { | |
723 | /* set periph PLL to safe starting threshold frequency */ | |
724 | if (ramp_required == 1) | |
725 | pll_ramp_periph_hz = | |
726 | CLKMGR_PLL_RAMP_MPUCLK_THRESHOLD_HZ; | |
727 | else if (ramp_required == 2) | |
728 | pll_ramp_periph_hz = | |
729 | CLKMGR_PLL_RAMP_NOCCLK_THRESHOLD_HZ; | |
730 | ||
94172c79 LFT |
731 | writel((per_cfg->vco1_denom << |
732 | CLKMGR_PERPLL_VCO1_DENOM_LSB) | | |
177ba1f9 LFT |
733 | cm_calc_safe_pll_numer(1, main_cfg, per_cfg, |
734 | pll_ramp_periph_hz), | |
94172c79 | 735 | socfpga_get_clkmgr_addr() + CLKMGR_A10_PERPLL_VCO1); |
177ba1f9 | 736 | } else |
94172c79 LFT |
737 | writel((per_cfg->vco1_denom << |
738 | CLKMGR_PERPLL_VCO1_DENOM_LSB) | | |
177ba1f9 | 739 | per_cfg->vco1_numer, |
94172c79 | 740 | socfpga_get_clkmgr_addr() + CLKMGR_A10_PERPLL_VCO1); |
177ba1f9 LFT |
741 | |
742 | /* Wait for at least 5 us */ | |
aea0e80a | 743 | sdelay(5000); |
177ba1f9 LFT |
744 | |
745 | /* Now deassert BGPWRDN and PWRDN */ | |
94172c79 | 746 | clrbits_le32(socfpga_get_clkmgr_addr() + CLKMGR_A10_MAINPLL_VCO0, |
177ba1f9 LFT |
747 | CLKMGR_MAINPLL_VCO0_BGPWRDN_SET_MSK | |
748 | CLKMGR_MAINPLL_VCO0_PWRDN_SET_MSK); | |
94172c79 | 749 | clrbits_le32(socfpga_get_clkmgr_addr() + CLKMGR_A10_PERPLL_VCO0, |
177ba1f9 LFT |
750 | CLKMGR_PERPLL_VCO0_BGPWRDN_SET_MSK | |
751 | CLKMGR_PERPLL_VCO0_PWRDN_SET_MSK); | |
752 | ||
753 | /* Wait for at least 7 us */ | |
aea0e80a | 754 | sdelay(7000); |
177ba1f9 LFT |
755 | |
756 | /* enable the VCO and disable the external regulator to PLL */ | |
94172c79 | 757 | writel((readl(socfpga_get_clkmgr_addr() + CLKMGR_A10_MAINPLL_VCO0) & |
177ba1f9 LFT |
758 | ~CLKMGR_MAINPLL_VCO0_REGEXTSEL_SET_MSK) | |
759 | CLKMGR_MAINPLL_VCO0_EN_SET_MSK, | |
94172c79 LFT |
760 | socfpga_get_clkmgr_addr() + CLKMGR_A10_MAINPLL_VCO0); |
761 | writel((readl(socfpga_get_clkmgr_addr() + CLKMGR_A10_PERPLL_VCO0) & | |
177ba1f9 LFT |
762 | ~CLKMGR_PERPLL_VCO0_REGEXTSEL_SET_MSK) | |
763 | CLKMGR_PERPLL_VCO0_EN_SET_MSK, | |
94172c79 | 764 | socfpga_get_clkmgr_addr() + CLKMGR_A10_PERPLL_VCO0); |
177ba1f9 LFT |
765 | |
766 | /* setup all the main PLL counter and clock source */ | |
767 | writel(main_cfg->nocclk, | |
94172c79 | 768 | socfpga_get_clkmgr_addr() + CLKMGR_A10_ALTR_NOCCLK); |
177ba1f9 | 769 | writel(main_cfg->mpuclk, |
94172c79 | 770 | socfpga_get_clkmgr_addr() + CLKMGR_A10_ALTR_MPUCLK); |
177ba1f9 LFT |
771 | |
772 | /* main_emaca_clk divider */ | |
94172c79 LFT |
773 | writel(main_cfg->cntr2clk_cnt, |
774 | socfpga_get_clkmgr_addr() + CLKMGR_A10_MAINPLL_CNTR2CLK); | |
177ba1f9 | 775 | /* main_emacb_clk divider */ |
94172c79 LFT |
776 | writel(main_cfg->cntr3clk_cnt, |
777 | socfpga_get_clkmgr_addr() + CLKMGR_A10_MAINPLL_CNTR3CLK); | |
177ba1f9 | 778 | /* main_emac_ptp_clk divider */ |
94172c79 LFT |
779 | writel(main_cfg->cntr4clk_cnt, |
780 | socfpga_get_clkmgr_addr() + CLKMGR_A10_MAINPLL_CNTR4CLK); | |
177ba1f9 | 781 | /* main_gpio_db_clk divider */ |
94172c79 LFT |
782 | writel(main_cfg->cntr5clk_cnt, |
783 | socfpga_get_clkmgr_addr() + CLKMGR_A10_MAINPLL_CNTR5CLK); | |
177ba1f9 | 784 | /* main_sdmmc_clk divider */ |
94172c79 LFT |
785 | writel(main_cfg->cntr6clk_cnt, |
786 | socfpga_get_clkmgr_addr() + CLKMGR_A10_MAINPLL_CNTR6CLK); | |
177ba1f9 LFT |
787 | /* main_s2f_user0_clk divider */ |
788 | writel(main_cfg->cntr7clk_cnt | | |
789 | (main_cfg->cntr7clk_src << CLKMGR_MAINPLL_CNTR7CLK_SRC_LSB), | |
94172c79 | 790 | socfpga_get_clkmgr_addr() + CLKMGR_A10_MAINPLL_CNTR7CLK); |
177ba1f9 | 791 | /* main_s2f_user1_clk divider */ |
94172c79 LFT |
792 | writel(main_cfg->cntr8clk_cnt, |
793 | socfpga_get_clkmgr_addr() + CLKMGR_A10_MAINPLL_CNTR8CLK); | |
177ba1f9 LFT |
794 | /* main_hmc_pll_clk divider */ |
795 | writel(main_cfg->cntr9clk_cnt | | |
796 | (main_cfg->cntr9clk_src << CLKMGR_MAINPLL_CNTR9CLK_SRC_LSB), | |
94172c79 | 797 | socfpga_get_clkmgr_addr() + CLKMGR_A10_MAINPLL_CNTR9CLK); |
177ba1f9 LFT |
798 | /* main_periph_ref_clk divider */ |
799 | writel(main_cfg->cntr15clk_cnt, | |
94172c79 | 800 | socfpga_get_clkmgr_addr() + CLKMGR_A10_MAINPLL_CNTR15CLK); |
177ba1f9 LFT |
801 | |
802 | /* setup all the peripheral PLL counter and clock source */ | |
803 | /* peri_emaca_clk divider */ | |
804 | writel(per_cfg->cntr2clk_cnt | | |
805 | (per_cfg->cntr2clk_src << CLKMGR_PERPLL_CNTR2CLK_SRC_LSB), | |
94172c79 | 806 | socfpga_get_clkmgr_addr() + CLKMGR_A10_PERPLL_CNTR2CLK); |
177ba1f9 LFT |
807 | /* peri_emacb_clk divider */ |
808 | writel(per_cfg->cntr3clk_cnt | | |
809 | (per_cfg->cntr3clk_src << CLKMGR_PERPLL_CNTR3CLK_SRC_LSB), | |
94172c79 | 810 | socfpga_get_clkmgr_addr() + CLKMGR_A10_PERPLL_CNTR3CLK); |
177ba1f9 LFT |
811 | /* peri_emac_ptp_clk divider */ |
812 | writel(per_cfg->cntr4clk_cnt | | |
813 | (per_cfg->cntr4clk_src << CLKMGR_PERPLL_CNTR4CLK_SRC_LSB), | |
94172c79 | 814 | socfpga_get_clkmgr_addr() + CLKMGR_A10_PERPLL_CNTR4CLK); |
177ba1f9 LFT |
815 | /* peri_gpio_db_clk divider */ |
816 | writel(per_cfg->cntr5clk_cnt | | |
817 | (per_cfg->cntr5clk_src << CLKMGR_PERPLL_CNTR5CLK_SRC_LSB), | |
94172c79 | 818 | socfpga_get_clkmgr_addr() + CLKMGR_A10_PERPLL_CNTR5CLK); |
177ba1f9 LFT |
819 | /* peri_sdmmc_clk divider */ |
820 | writel(per_cfg->cntr6clk_cnt | | |
821 | (per_cfg->cntr6clk_src << CLKMGR_PERPLL_CNTR6CLK_SRC_LSB), | |
94172c79 | 822 | socfpga_get_clkmgr_addr() + CLKMGR_A10_PERPLL_CNTR6CLK); |
177ba1f9 | 823 | /* peri_s2f_user0_clk divider */ |
94172c79 LFT |
824 | writel(per_cfg->cntr7clk_cnt, |
825 | socfpga_get_clkmgr_addr() + CLKMGR_A10_PERPLL_CNTR7CLK); | |
177ba1f9 LFT |
826 | /* peri_s2f_user1_clk divider */ |
827 | writel(per_cfg->cntr8clk_cnt | | |
828 | (per_cfg->cntr8clk_src << CLKMGR_PERPLL_CNTR8CLK_SRC_LSB), | |
94172c79 | 829 | socfpga_get_clkmgr_addr() + CLKMGR_A10_PERPLL_CNTR8CLK); |
177ba1f9 | 830 | /* peri_hmc_pll_clk divider */ |
94172c79 LFT |
831 | writel(per_cfg->cntr9clk_cnt, |
832 | socfpga_get_clkmgr_addr() + CLKMGR_A10_PERPLL_CNTR9CLK); | |
177ba1f9 LFT |
833 | |
834 | /* setup all the external PLL counter */ | |
835 | /* mpu wrapper / external divider */ | |
836 | writel(main_cfg->mpuclk_cnt | | |
837 | (main_cfg->mpuclk_src << CLKMGR_MAINPLL_MPUCLK_SRC_LSB), | |
94172c79 | 838 | socfpga_get_clkmgr_addr() + CLKMGR_A10_MAINPLL_MPUCLK); |
177ba1f9 LFT |
839 | /* NOC wrapper / external divider */ |
840 | writel(main_cfg->nocclk_cnt | | |
841 | (main_cfg->nocclk_src << CLKMGR_MAINPLL_NOCCLK_SRC_LSB), | |
94172c79 | 842 | socfpga_get_clkmgr_addr() + CLKMGR_A10_MAINPLL_NOCCLK); |
177ba1f9 LFT |
843 | /* NOC subclock divider such as l4 */ |
844 | writel(main_cfg->nocdiv_l4mainclk | | |
845 | (main_cfg->nocdiv_l4mpclk << | |
846 | CLKMGR_MAINPLL_NOCDIV_L4MPCLK_LSB) | | |
847 | (main_cfg->nocdiv_l4spclk << | |
848 | CLKMGR_MAINPLL_NOCDIV_L4SPCLK_LSB) | | |
849 | (main_cfg->nocdiv_csatclk << | |
850 | CLKMGR_MAINPLL_NOCDIV_CSATCLK_LSB) | | |
851 | (main_cfg->nocdiv_cstraceclk << | |
852 | CLKMGR_MAINPLL_NOCDIV_CSTRACECLK_LSB) | | |
853 | (main_cfg->nocdiv_cspdbclk << | |
854 | CLKMGR_MAINPLL_NOCDIV_CSPDBGCLK_LSB), | |
94172c79 | 855 | socfpga_get_clkmgr_addr() + CLKMGR_A10_MAINPLL_NOCDIV); |
177ba1f9 LFT |
856 | /* gpio_db external divider */ |
857 | writel(per_cfg->gpiodiv_gpiodbclk, | |
94172c79 | 858 | socfpga_get_clkmgr_addr() + CLKMGR_A10_PERPLL_GPIOFIV); |
177ba1f9 LFT |
859 | |
860 | /* setup the EMAC clock mux select */ | |
861 | writel((per_cfg->emacctl_emac0sel << | |
862 | CLKMGR_PERPLL_EMACCTL_EMAC0SEL_LSB) | | |
863 | (per_cfg->emacctl_emac1sel << | |
864 | CLKMGR_PERPLL_EMACCTL_EMAC1SEL_LSB) | | |
865 | (per_cfg->emacctl_emac2sel << | |
866 | CLKMGR_PERPLL_EMACCTL_EMAC2SEL_LSB), | |
94172c79 | 867 | socfpga_get_clkmgr_addr() + CLKMGR_A10_PERPLL_EMACCTL); |
177ba1f9 LFT |
868 | |
869 | /* at this stage, check for PLL lock status */ | |
870 | cm_wait_for_lock(LOCKED_MASK); | |
871 | ||
872 | /* | |
873 | * after locking, but before taking out of bypass, | |
874 | * assert/deassert outresetall | |
875 | */ | |
876 | /* assert mainpll outresetall */ | |
94172c79 | 877 | setbits_le32(socfpga_get_clkmgr_addr() + CLKMGR_A10_MAINPLL_VCO0, |
177ba1f9 LFT |
878 | CLKMGR_MAINPLL_VCO0_OUTRSTALL_SET_MSK); |
879 | /* assert perpll outresetall */ | |
94172c79 | 880 | setbits_le32(socfpga_get_clkmgr_addr() + CLKMGR_A10_PERPLL_VCO0, |
177ba1f9 LFT |
881 | CLKMGR_PERPLL_VCO0_OUTRSTALL_SET_MSK); |
882 | /* de-assert mainpll outresetall */ | |
94172c79 | 883 | clrbits_le32(socfpga_get_clkmgr_addr() + CLKMGR_A10_MAINPLL_VCO0, |
177ba1f9 LFT |
884 | CLKMGR_MAINPLL_VCO0_OUTRSTALL_SET_MSK); |
885 | /* de-assert perpll outresetall */ | |
94172c79 | 886 | clrbits_le32(socfpga_get_clkmgr_addr() + CLKMGR_A10_PERPLL_VCO0, |
177ba1f9 LFT |
887 | CLKMGR_PERPLL_VCO0_OUTRSTALL_SET_MSK); |
888 | ||
889 | /* Take all PLLs out of bypass when boot mode is cleared. */ | |
890 | /* release mainpll from bypass */ | |
891 | writel(CLKMGR_MAINPLL_BYPASS_RESET, | |
94172c79 | 892 | socfpga_get_clkmgr_addr() + CLKMGR_A10_MAINPLL_BYPASSR); |
177ba1f9 | 893 | /* wait till Clock Manager is not busy */ |
aea0e80a | 894 | cm_busy_wait_for_fsm(); |
177ba1f9 LFT |
895 | |
896 | /* release perpll from bypass */ | |
897 | writel(CLKMGR_PERPLL_BYPASS_RESET, | |
94172c79 | 898 | socfpga_get_clkmgr_addr() + CLKMGR_A10_PERPLL_BYPASSR); |
177ba1f9 | 899 | /* wait till Clock Manager is not busy */ |
aea0e80a | 900 | cm_busy_wait_for_fsm(); |
177ba1f9 LFT |
901 | |
902 | /* clear boot mode */ | |
94172c79 | 903 | clrbits_le32(socfpga_get_clkmgr_addr() + CLKMGR_A10_CTRL, |
177ba1f9 LFT |
904 | CLKMGR_CLKMGR_CTL_BOOTMOD_SET_MSK); |
905 | /* wait till Clock Manager is not busy */ | |
aea0e80a | 906 | cm_busy_wait_for_fsm(); |
177ba1f9 LFT |
907 | |
908 | /* At here, we need to ramp to final value if needed */ | |
909 | if (pll_ramp_main_hz != 0) | |
910 | cm_pll_ramp_main(main_cfg, per_cfg, pll_ramp_main_hz); | |
911 | if (pll_ramp_periph_hz != 0) | |
912 | cm_pll_ramp_periph(main_cfg, per_cfg, pll_ramp_periph_hz); | |
913 | ||
914 | /* Now ungate non-hw-managed clocks */ | |
915 | writel(CLKMGR_MAINPLL_EN_S2FUSER0CLKEN_SET_MSK | | |
94172c79 LFT |
916 | CLKMGR_MAINPLL_EN_HMCPLLREFCLKEN_SET_MSK, |
917 | socfpga_get_clkmgr_addr() + CLKMGR_A10_MAINPLL_ENS); | |
918 | writel(CLKMGR_PERPLL_EN_RESET, | |
919 | socfpga_get_clkmgr_addr() + CLKMGR_A10_PERPLL_ENS); | |
177ba1f9 LFT |
920 | |
921 | /* Clear the loss lock and slip bits as they might set during | |
922 | clock reconfiguration */ | |
923 | writel(CLKMGR_CLKMGR_INTR_MAINPLLLOST_SET_MSK | | |
924 | CLKMGR_CLKMGR_INTR_PERPLLLOST_SET_MSK | | |
925 | CLKMGR_CLKMGR_INTR_MAINPLLRFSLIP_SET_MSK | | |
926 | CLKMGR_CLKMGR_INTR_PERPLLRFSLIP_SET_MSK | | |
927 | CLKMGR_CLKMGR_INTR_MAINPLLFBSLIP_SET_MSK | | |
928 | CLKMGR_CLKMGR_INTR_PERPLLFBSLIP_SET_MSK, | |
94172c79 | 929 | socfpga_get_clkmgr_addr() + CLKMGR_A10_INTR); |
177ba1f9 LFT |
930 | |
931 | return 0; | |
932 | } | |
933 | ||
0b8f6378 | 934 | static void cm_use_intosc(void) |
177ba1f9 | 935 | { |
94172c79 | 936 | setbits_le32(socfpga_get_clkmgr_addr() + CLKMGR_A10_CTRL, |
177ba1f9 LFT |
937 | CLKMGR_CLKMGR_CTL_BOOTCLK_INTOSC_SET_MSK); |
938 | } | |
939 | ||
177ba1f9 LFT |
940 | int cm_basic_init(const void *blob) |
941 | { | |
942 | struct mainpll_cfg main_cfg; | |
943 | struct perpll_cfg per_cfg; | |
177ba1f9 LFT |
944 | int rval; |
945 | ||
946 | /* initialize to zero for use case of optional node */ | |
947 | memset(&main_cfg, 0, sizeof(main_cfg)); | |
948 | memset(&per_cfg, 0, sizeof(per_cfg)); | |
177ba1f9 | 949 | |
480f7f9c | 950 | rval = of_get_clk_cfg(blob, &main_cfg, &per_cfg); |
177ba1f9 LFT |
951 | if (rval) |
952 | return rval; | |
953 | ||
0b8f6378 MV |
954 | cm_use_intosc(); |
955 | ||
f4c3e0dc | 956 | return cm_full_cfg(&main_cfg, &per_cfg); |
177ba1f9 | 957 | } |
0b8f6378 | 958 | #endif |
177ba1f9 | 959 | |
d81b5da3 | 960 | static u32 cm_get_rate_dm(char *name) |
177ba1f9 | 961 | { |
d81b5da3 MV |
962 | struct uclass *uc; |
963 | struct udevice *dev = NULL; | |
964 | struct clk clk = { 0 }; | |
d81b5da3 MV |
965 | int ret; |
966 | ||
967 | /* Device addresses start at 1 */ | |
968 | ret = uclass_get(UCLASS_CLK, &uc); | |
969 | if (ret) | |
177ba1f9 | 970 | return 0; |
177ba1f9 | 971 | |
d81b5da3 MV |
972 | ret = uclass_get_device_by_name(UCLASS_CLK, name, &dev); |
973 | if (ret) | |
177ba1f9 | 974 | return 0; |
177ba1f9 | 975 | |
d81b5da3 MV |
976 | ret = device_probe(dev); |
977 | if (ret) | |
177ba1f9 | 978 | return 0; |
177ba1f9 | 979 | |
d81b5da3 MV |
980 | ret = clk_request(dev, &clk); |
981 | if (ret) | |
982 | return 0; | |
177ba1f9 | 983 | |
c9309f40 | 984 | return clk_get_rate(&clk); |
177ba1f9 LFT |
985 | } |
986 | ||
d81b5da3 | 987 | static u32 cm_get_rate_dm_khz(char *name) |
177ba1f9 | 988 | { |
d81b5da3 | 989 | return cm_get_rate_dm(name) / 1000; |
177ba1f9 LFT |
990 | } |
991 | ||
d81b5da3 | 992 | unsigned long cm_get_mpu_clk_hz(void) |
177ba1f9 | 993 | { |
d81b5da3 | 994 | return cm_get_rate_dm("main_mpu_base_clk"); |
177ba1f9 LFT |
995 | } |
996 | ||
997 | unsigned int cm_get_qspi_controller_clk_hz(void) | |
998 | { | |
d81b5da3 | 999 | return cm_get_rate_dm("qspi_clk"); |
177ba1f9 LFT |
1000 | } |
1001 | ||
d81b5da3 | 1002 | unsigned int cm_get_l4_sp_clk_hz(void) |
21143ce1 | 1003 | { |
d81b5da3 | 1004 | return cm_get_rate_dm("l4_sp_clk"); |
21143ce1 EP |
1005 | } |
1006 | ||
177ba1f9 LFT |
1007 | void cm_print_clock_quick_summary(void) |
1008 | { | |
d81b5da3 MV |
1009 | printf("MPU %10d kHz\n", cm_get_rate_dm_khz("main_mpu_base_clk")); |
1010 | printf("MMC %8d kHz\n", cm_get_rate_dm_khz("sdmmc_clk")); | |
1011 | printf("QSPI %8d kHz\n", cm_get_rate_dm_khz("qspi_clk")); | |
1012 | printf("SPI %8d kHz\n", cm_get_rate_dm_khz("spi_m_clk")); | |
1013 | printf("EOSC1 %8d kHz\n", cm_get_rate_dm_khz("osc1")); | |
1014 | printf("cb_intosc %8d kHz\n", cm_get_rate_dm_khz("cb_intosc_ls_clk")); | |
1015 | printf("f2s_free %8d kHz\n", cm_get_rate_dm_khz("f2s_free_clk")); | |
1016 | printf("Main VCO %8d kHz\n", cm_get_rate_dm_khz("main_pll@40")); | |
1017 | printf("NOC %8d kHz\n", cm_get_rate_dm_khz("main_noc_base_clk")); | |
1018 | printf("L4 Main %8d kHz\n", cm_get_rate_dm_khz("l4_main_clk")); | |
1019 | printf("L4 MP %8d kHz\n", cm_get_rate_dm_khz("l4_mp_clk")); | |
1020 | printf("L4 SP %8d kHz\n", cm_get_rate_dm_khz("l4_sp_clk")); | |
1021 | printf("L4 sys free %8d kHz\n", cm_get_rate_dm_khz("l4_sys_free_clk")); | |
177ba1f9 | 1022 | } |