blob: 3fa19e05c47ef91c183e2034f620100138283030 [file] [log] [blame]
Teik Heng Chong8ab95782022-06-29 13:51:50 +08001// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
Siew Chin Lim1557df82021-08-10 11:26:30 +08002/*
Teik Heng Chong8ab95782022-06-29 13:51:50 +08003 * Copyright (C) 2020-2022 Intel Corporation <www.intel.com>
Siew Chin Lim1557df82021-08-10 11:26:30 +08004 */
5
6#include <common.h>
7#include <asm/arch/clock_manager.h>
8#include <asm/global_data.h>
9#include <asm/io.h>
10#include <clk-uclass.h>
11#include <dm.h>
12#include <dm/lists.h>
13#include <dm/util.h>
14#include <dt-bindings/clock/n5x-clock.h>
15
16DECLARE_GLOBAL_DATA_PTR;
17
18struct socfpga_clk_plat {
19 void __iomem *regs;
20};
21
22/*
23 * function to write the bypass register which requires a poll of the
24 * busy bit
25 */
26static void clk_write_bypass_mainpll(struct socfpga_clk_plat *plat, u32 val)
27{
28 CM_REG_WRITEL(plat, val, CLKMGR_MAINPLL_BYPASS);
29 cm_wait_for_fsm();
30}
31
32static void clk_write_bypass_perpll(struct socfpga_clk_plat *plat, u32 val)
33{
34 CM_REG_WRITEL(plat, val, CLKMGR_PERPLL_BYPASS);
35 cm_wait_for_fsm();
36}
37
38/* function to write the ctrl register which requires a poll of the busy bit */
39static void clk_write_ctrl(struct socfpga_clk_plat *plat, u32 val)
40{
41 CM_REG_WRITEL(plat, val, CLKMGR_CTRL);
42 cm_wait_for_fsm();
43}
44
45/*
46 * Setup clocks while making no assumptions about previous state of the clocks.
47 */
48static void clk_basic_init(struct udevice *dev,
49 const struct cm_config * const cfg)
50{
51 struct socfpga_clk_plat *plat = dev_get_plat(dev);
52
53 if (!cfg)
54 return;
55
56#if IS_ENABLED(CONFIG_SPL_BUILD)
57 /* Always force clock manager into boot mode before any configuration */
58 clk_write_ctrl(plat,
59 CM_REG_READL(plat, CLKMGR_CTRL) | CLKMGR_CTRL_BOOTMODE);
60#else
61 /* Skip clock configuration in SSBL if it's not in boot mode */
62 if (!(CM_REG_READL(plat, CLKMGR_CTRL) & CLKMGR_CTRL_BOOTMODE))
63 return;
64#endif
65
66 /* Put both PLLs in bypass */
67 clk_write_bypass_mainpll(plat, CLKMGR_BYPASS_MAINPLL_ALL);
68 clk_write_bypass_perpll(plat, CLKMGR_BYPASS_PERPLL_ALL);
69
70 /* Put both PLLs in Reset */
71 CM_REG_SETBITS(plat, CLKMGR_MAINPLL_PLLCTRL,
72 CLKMGR_PLLCTRL_BYPASS_MASK);
73 CM_REG_SETBITS(plat, CLKMGR_PERPLL_PLLCTRL,
74 CLKMGR_PLLCTRL_BYPASS_MASK);
75
76 /* setup main PLL */
77 CM_REG_WRITEL(plat, cfg->main_pll_pllglob, CLKMGR_MAINPLL_PLLGLOB);
78 CM_REG_WRITEL(plat, cfg->main_pll_plldiv, CLKMGR_MAINPLL_PLLDIV);
79 CM_REG_WRITEL(plat, cfg->main_pll_plloutdiv, CLKMGR_MAINPLL_PLLOUTDIV);
80 CM_REG_WRITEL(plat, cfg->main_pll_mpuclk, CLKMGR_MAINPLL_MPUCLK);
81 CM_REG_WRITEL(plat, cfg->main_pll_nocclk, CLKMGR_MAINPLL_NOCCLK);
82 CM_REG_WRITEL(plat, cfg->main_pll_nocdiv, CLKMGR_MAINPLL_NOCDIV);
83
84 /* setup peripheral */
85 CM_REG_WRITEL(plat, cfg->per_pll_pllglob, CLKMGR_PERPLL_PLLGLOB);
86 CM_REG_WRITEL(plat, cfg->per_pll_plldiv, CLKMGR_PERPLL_PLLDIV);
87 CM_REG_WRITEL(plat, cfg->per_pll_plloutdiv, CLKMGR_PERPLL_PLLOUTDIV);
88 CM_REG_WRITEL(plat, cfg->per_pll_emacctl, CLKMGR_PERPLL_EMACCTL);
89 CM_REG_WRITEL(plat, cfg->per_pll_gpiodiv, CLKMGR_PERPLL_GPIODIV);
90
91 /* Take both PLL out of reset and power up */
92 CM_REG_CLRBITS(plat, CLKMGR_MAINPLL_PLLCTRL,
93 CLKMGR_PLLCTRL_BYPASS_MASK);
94 CM_REG_CLRBITS(plat, CLKMGR_PERPLL_PLLCTRL,
95 CLKMGR_PLLCTRL_BYPASS_MASK);
96
97 cm_wait_for_lock(CLKMGR_STAT_ALLPLL_LOCKED_MASK);
98
99 CM_REG_WRITEL(plat, cfg->alt_emacactr, CLKMGR_ALTR_EMACACTR);
100 CM_REG_WRITEL(plat, cfg->alt_emacbctr, CLKMGR_ALTR_EMACBCTR);
101 CM_REG_WRITEL(plat, cfg->alt_emacptpctr, CLKMGR_ALTR_EMACPTPCTR);
102 CM_REG_WRITEL(plat, cfg->alt_gpiodbctr, CLKMGR_ALTR_GPIODBCTR);
103 CM_REG_WRITEL(plat, cfg->alt_sdmmcctr, CLKMGR_ALTR_SDMMCCTR);
104 CM_REG_WRITEL(plat, cfg->alt_s2fuser0ctr, CLKMGR_ALTR_S2FUSER0CTR);
105 CM_REG_WRITEL(plat, cfg->alt_s2fuser1ctr, CLKMGR_ALTR_S2FUSER1CTR);
106 CM_REG_WRITEL(plat, cfg->alt_psirefctr, CLKMGR_ALTR_PSIREFCTR);
107
108 /* Configure ping pong counters in altera group */
109 CM_REG_WRITEL(plat, CLKMGR_LOSTLOCK_SET_MASK, CLKMGR_MAINPLL_LOSTLOCK);
110 CM_REG_WRITEL(plat, CLKMGR_LOSTLOCK_SET_MASK, CLKMGR_PERPLL_LOSTLOCK);
111
112 CM_REG_WRITEL(plat, CM_REG_READL(plat, CLKMGR_MAINPLL_PLLGLOB) |
113 CLKMGR_PLLGLOB_CLR_LOSTLOCK_BYPASS_MASK,
114 CLKMGR_MAINPLL_PLLGLOB);
115 CM_REG_WRITEL(plat, CM_REG_READL(plat, CLKMGR_PERPLL_PLLGLOB) |
116 CLKMGR_PLLGLOB_CLR_LOSTLOCK_BYPASS_MASK,
117 CLKMGR_PERPLL_PLLGLOB);
118
119 /* Take all PLLs out of bypass */
120 clk_write_bypass_mainpll(plat, 0);
121 clk_write_bypass_perpll(plat, 0);
122
123 /* Clear the loss of lock bits */
124 CM_REG_CLRBITS(plat, CLKMGR_INTRCLR,
125 CLKMGR_INTER_PERPLLLOST_MASK |
126 CLKMGR_INTER_MAINPLLLOST_MASK);
127
128 /* Take all ping pong counters out of reset */
129 CM_REG_CLRBITS(plat, CLKMGR_ALTR_EXTCNTRST,
130 CLKMGR_ALT_EXTCNTRST_ALLCNTRST_MASK);
131
132 /* Out of boot mode */
133 clk_write_ctrl(plat,
134 CM_REG_READL(plat, CLKMGR_CTRL) & ~CLKMGR_CTRL_BOOTMODE);
135}
136
137static u32 clk_get_5_1_clk_src(struct socfpga_clk_plat *plat, u32 reg)
138{
139 u32 clksrc = CM_REG_READL(plat, reg);
140
141 return (clksrc & CLKMGR_CLKSRC_MASK) >> CLKMGR_CLKSRC_OFFSET;
142}
143
144static u64 clk_get_pll_output_hz(struct socfpga_clk_plat *plat,
145 u32 pllglob_reg, u32 plldiv_reg)
146{
147 u64 clock = 0;
148 u32 clklsrc, divf, divr, divq, power = 1;
149
150 /* Get input clock frequency */
151 clklsrc = (CM_REG_READL(plat, pllglob_reg) &
152 CLKMGR_PLLGLOB_VCO_PSRC_MASK) >>
153 CLKMGR_PLLGLOB_VCO_PSRC_OFFSET;
154
155 switch (clklsrc) {
156 case CLKMGR_VCO_PSRC_EOSC1:
157 clock = cm_get_osc_clk_hz();
158 break;
159 case CLKMGR_VCO_PSRC_INTOSC:
160 clock = cm_get_intosc_clk_hz();
161 break;
162 case CLKMGR_VCO_PSRC_F2S:
163 clock = cm_get_fpga_clk_hz();
164 break;
165 }
166
167 /* Calculate pll out clock frequency */
168 divf = (CM_REG_READL(plat, plldiv_reg) &
169 CLKMGR_PLLDIV_FDIV_MASK) >>
170 CLKMGR_PLLDIV_FDIV_OFFSET;
171
172 divr = (CM_REG_READL(plat, plldiv_reg) &
173 CLKMGR_PLLDIV_REFCLKDIV_MASK) >>
174 CLKMGR_PLLDIV_REFCLKDIV_OFFSET;
175
176 divq = (CM_REG_READL(plat, plldiv_reg) &
177 CLKMGR_PLLDIV_OUTDIV_QDIV_MASK) >>
178 CLKMGR_PLLDIV_OUTDIV_QDIV_OFFSET;
179
180 while (divq) {
181 power *= 2;
182 divq--;
183 }
184
185 return (clock * 2 * (divf + 1)) / ((divr + 1) * power);
186}
187
188static u64 clk_get_clksrc_hz(struct socfpga_clk_plat *plat, u32 clksrc_reg,
189 u32 main_div, u32 per_div)
190{
191 u64 clock = 0;
192 u32 clklsrc = clk_get_5_1_clk_src(plat, clksrc_reg);
193
194 switch (clklsrc) {
195 case CLKMGR_CLKSRC_MAIN:
196 clock = clk_get_pll_output_hz(plat,
197 CLKMGR_MAINPLL_PLLGLOB,
198 CLKMGR_MAINPLL_PLLDIV);
199 clock /= 1 + main_div;
200 break;
201
202 case CLKMGR_CLKSRC_PER:
203 clock = clk_get_pll_output_hz(plat,
204 CLKMGR_PERPLL_PLLGLOB,
205 CLKMGR_PERPLL_PLLDIV);
206 clock /= 1 + per_div;
207 break;
208
209 case CLKMGR_CLKSRC_OSC1:
210 clock = cm_get_osc_clk_hz();
211 break;
212
213 case CLKMGR_CLKSRC_INTOSC:
214 clock = cm_get_intosc_clk_hz();
215 break;
216
217 case CLKMGR_CLKSRC_FPGA:
218 clock = cm_get_fpga_clk_hz();
219 break;
220 default:
221 return 0;
222 }
223
224 return clock;
225}
226
227static u64 clk_get_mpu_clk_hz(struct socfpga_clk_plat *plat)
228{
229 u32 mainpll_c0cnt = (CM_REG_READL(plat, CLKMGR_MAINPLL_PLLOUTDIV) &
230 CLKMGR_PLLOUTDIV_C0CNT_MASK) >>
231 CLKMGR_PLLOUTDIV_C0CNT_OFFSET;
232
233 u32 perpll_c0cnt = (CM_REG_READL(plat, CLKMGR_PERPLL_PLLOUTDIV) &
234 CLKMGR_PLLOUTDIV_C0CNT_MASK) >>
235 CLKMGR_PLLOUTDIV_C0CNT_OFFSET;
236
237 u64 clock = clk_get_clksrc_hz(plat, CLKMGR_MAINPLL_MPUCLK,
238 mainpll_c0cnt, perpll_c0cnt);
239
240 clock /= 1 + (CM_REG_READL(plat, CLKMGR_MAINPLL_MPUCLK) &
241 CLKMGR_CLKCNT_MSK);
242
243 return clock;
244}
245
246static u32 clk_get_l3_main_clk_hz(struct socfpga_clk_plat *plat)
247{
248 u32 mainpll_c1cnt = (CM_REG_READL(plat, CLKMGR_MAINPLL_PLLOUTDIV) &
249 CLKMGR_PLLOUTDIV_C1CNT_MASK) >>
250 CLKMGR_PLLOUTDIV_C1CNT_OFFSET;
251
252 u32 perpll_c1cnt = (CM_REG_READL(plat, CLKMGR_PERPLL_PLLOUTDIV) &
253 CLKMGR_PLLOUTDIV_C1CNT_MASK) >>
254 CLKMGR_PLLOUTDIV_C1CNT_OFFSET;
255
256 return clk_get_clksrc_hz(plat, CLKMGR_MAINPLL_NOCCLK,
257 mainpll_c1cnt, perpll_c1cnt);
258}
259
260static u32 clk_get_l4_main_clk_hz(struct socfpga_clk_plat *plat)
261{
262 u64 clock = clk_get_l3_main_clk_hz(plat);
263
264 clock /= BIT((CM_REG_READL(plat, CLKMGR_MAINPLL_NOCDIV) >>
265 CLKMGR_NOCDIV_L4MAIN_OFFSET) &
266 CLKMGR_NOCDIV_DIVIDER_MASK);
267
268 return clock;
269}
270
271static u32 clk_get_sdmmc_clk_hz(struct socfpga_clk_plat *plat)
272{
273 u32 mainpll_c3cnt = (CM_REG_READL(plat, CLKMGR_MAINPLL_PLLOUTDIV) &
274 CLKMGR_PLLOUTDIV_C3CNT_MASK) >>
275 CLKMGR_PLLOUTDIV_C3CNT_OFFSET;
276
277 u32 perpll_c3cnt = (CM_REG_READL(plat, CLKMGR_PERPLL_PLLOUTDIV) &
278 CLKMGR_PLLOUTDIV_C3CNT_MASK) >>
279 CLKMGR_PLLOUTDIV_C3CNT_OFFSET;
280
281 u64 clock = clk_get_clksrc_hz(plat, CLKMGR_ALTR_SDMMCCTR,
282 mainpll_c3cnt, perpll_c3cnt);
283
284 clock /= 1 + (CM_REG_READL(plat, CLKMGR_ALTR_SDMMCCTR) &
285 CLKMGR_CLKCNT_MSK);
286
287 return clock / 4;
288}
289
290static u32 clk_get_l4_sp_clk_hz(struct socfpga_clk_plat *plat)
291{
292 u64 clock = clk_get_l3_main_clk_hz(plat);
293
294 clock /= BIT((CM_REG_READL(plat, CLKMGR_MAINPLL_NOCDIV) >>
295 CLKMGR_NOCDIV_L4SPCLK_OFFSET) &
296 CLKMGR_NOCDIV_DIVIDER_MASK);
297
298 return clock;
299}
300
301static u32 clk_get_l4_mp_clk_hz(struct socfpga_clk_plat *plat)
302{
303 u64 clock = clk_get_l3_main_clk_hz(plat);
304
305 clock /= BIT((CM_REG_READL(plat, CLKMGR_MAINPLL_NOCDIV) >>
306 CLKMGR_NOCDIV_L4MPCLK_OFFSET) &
307 CLKMGR_NOCDIV_DIVIDER_MASK);
308
309 return clock;
310}
311
312static u32 clk_get_l4_sys_free_clk_hz(struct socfpga_clk_plat *plat)
313{
314 if (CM_REG_READL(plat, CLKMGR_STAT) & CLKMGR_STAT_BOOTMODE)
315 return clk_get_l3_main_clk_hz(plat) / 2;
316
317 return clk_get_l3_main_clk_hz(plat) / 4;
318}
319
320static u32 clk_get_emac_clk_hz(struct socfpga_clk_plat *plat, u32 emac_id)
321{
322 bool emacsel_a;
323 u32 ctl;
324 u32 ctr_reg;
325 u32 clock;
326 u32 div;
327 u32 reg;
328
329 /* Get EMAC clock source */
330 ctl = CM_REG_READL(plat, CLKMGR_PERPLL_EMACCTL);
331 if (emac_id == N5X_EMAC0_CLK)
332 ctl = (ctl >> CLKMGR_PERPLLGRP_EMACCTL_EMAC0SELB_OFFSET) &
333 CLKMGR_PERPLLGRP_EMACCTL_EMAC0SELB_MASK;
334 else if (emac_id == N5X_EMAC1_CLK)
335 ctl = (ctl >> CLKMGR_PERPLLGRP_EMACCTL_EMAC1SELB_OFFSET) &
336 CLKMGR_PERPLLGRP_EMACCTL_EMAC1SELB_MASK;
337 else if (emac_id == N5X_EMAC2_CLK)
338 ctl = (ctl >> CLKMGR_PERPLLGRP_EMACCTL_EMAC2SELB_OFFSET) &
339 CLKMGR_PERPLLGRP_EMACCTL_EMAC2SELB_MASK;
340 else
341 return 0;
342
343 if (ctl) {
344 /* EMAC B source */
345 emacsel_a = false;
346 ctr_reg = CLKMGR_ALTR_EMACBCTR;
347 } else {
348 /* EMAC A source */
349 emacsel_a = true;
350 ctr_reg = CLKMGR_ALTR_EMACACTR;
351 }
352
353 reg = CM_REG_READL(plat, ctr_reg);
354 clock = (reg & CLKMGR_ALT_EMACCTR_SRC_MASK)
355 >> CLKMGR_ALT_EMACCTR_SRC_OFFSET;
356 div = (reg & CLKMGR_ALT_EMACCTR_CNT_MASK)
357 >> CLKMGR_ALT_EMACCTR_CNT_OFFSET;
358
359 switch (clock) {
360 case CLKMGR_CLKSRC_MAIN:
361 clock = clk_get_pll_output_hz(plat,
362 CLKMGR_MAINPLL_PLLGLOB,
363 CLKMGR_MAINPLL_PLLDIV);
364
365 if (emacsel_a) {
366 clock /= 1 + ((CM_REG_READL(plat,
367 CLKMGR_MAINPLL_PLLOUTDIV) &
368 CLKMGR_PLLOUTDIV_C2CNT_MASK) >>
369 CLKMGR_PLLOUTDIV_C2CNT_OFFSET);
370 } else {
371 clock /= 1 + ((CM_REG_READL(plat,
372 CLKMGR_MAINPLL_PLLOUTDIV) &
373 CLKMGR_PLLOUTDIV_C3CNT_MASK) >>
374 CLKMGR_PLLOUTDIV_C3CNT_OFFSET);
375 }
376 break;
377
378 case CLKMGR_CLKSRC_PER:
379 clock = clk_get_pll_output_hz(plat,
380 CLKMGR_PERPLL_PLLGLOB,
381 CLKMGR_PERPLL_PLLDIV);
382 if (emacsel_a) {
383 clock /= 1 + ((CM_REG_READL(plat,
384 CLKMGR_PERPLL_PLLOUTDIV) &
385 CLKMGR_PLLOUTDIV_C2CNT_MASK) >>
386 CLKMGR_PLLOUTDIV_C2CNT_OFFSET);
387 } else {
388 clock /= 1 + ((CM_REG_READL(plat,
389 CLKMGR_PERPLL_PLLOUTDIV) &
390 CLKMGR_PLLOUTDIV_C3CNT_MASK >>
391 CLKMGR_PLLOUTDIV_C3CNT_OFFSET));
392 }
393 break;
394
395 case CLKMGR_CLKSRC_OSC1:
396 clock = cm_get_osc_clk_hz();
397 break;
398
399 case CLKMGR_CLKSRC_INTOSC:
400 clock = cm_get_intosc_clk_hz();
401 break;
402
403 case CLKMGR_CLKSRC_FPGA:
404 clock = cm_get_fpga_clk_hz();
405 break;
406 }
407
408 clock /= 1 + div;
409
410 return clock;
411}
412
413static ulong socfpga_clk_get_rate(struct clk *clk)
414{
415 struct socfpga_clk_plat *plat = dev_get_plat(clk->dev);
416
417 switch (clk->id) {
418 case N5X_MPU_CLK:
419 return clk_get_mpu_clk_hz(plat);
420 case N5X_L4_MAIN_CLK:
421 return clk_get_l4_main_clk_hz(plat);
422 case N5X_L4_SYS_FREE_CLK:
423 return clk_get_l4_sys_free_clk_hz(plat);
424 case N5X_L4_MP_CLK:
425 return clk_get_l4_mp_clk_hz(plat);
426 case N5X_L4_SP_CLK:
427 return clk_get_l4_sp_clk_hz(plat);
428 case N5X_SDMMC_CLK:
429 return clk_get_sdmmc_clk_hz(plat);
430 case N5X_EMAC0_CLK:
431 case N5X_EMAC1_CLK:
432 case N5X_EMAC2_CLK:
433 return clk_get_emac_clk_hz(plat, clk->id);
434 case N5X_USB_CLK:
435 case N5X_NAND_X_CLK:
436 return clk_get_l4_mp_clk_hz(plat);
437 case N5X_NAND_CLK:
438 return clk_get_l4_mp_clk_hz(plat) / 4;
439 default:
440 return -ENXIO;
441 }
442}
443
444static int socfpga_clk_enable(struct clk *clk)
445{
446 return 0;
447}
448
449static int socfpga_clk_probe(struct udevice *dev)
450{
451 const struct cm_config *cm_default_cfg = cm_get_default_config();
452
453 clk_basic_init(dev, cm_default_cfg);
454
455 return 0;
456}
457
458static int socfpga_clk_of_to_plat(struct udevice *dev)
459{
460 struct socfpga_clk_plat *plat = dev_get_plat(dev);
461 fdt_addr_t addr;
462
463 addr = devfdt_get_addr(dev);
464 if (addr == FDT_ADDR_T_NONE)
465 return -EINVAL;
466 plat->regs = (void __iomem *)addr;
467
468 return 0;
469}
470
471static struct clk_ops socfpga_clk_ops = {
472 .enable = socfpga_clk_enable,
473 .get_rate = socfpga_clk_get_rate,
474};
475
476static const struct udevice_id socfpga_clk_match[] = {
477 { .compatible = "intel,n5x-clkmgr" },
478 {}
479};
480
481U_BOOT_DRIVER(socfpga_n5x_clk) = {
482 .name = "clk-n5x",
483 .id = UCLASS_CLK,
484 .of_match = socfpga_clk_match,
485 .ops = &socfpga_clk_ops,
486 .probe = socfpga_clk_probe,
487 .of_to_plat = socfpga_clk_of_to_plat,
488 .plat_auto = sizeof(struct socfpga_clk_plat),
489};