1 /*
2  * Copyright (c) 2019-2022, Intel Corporation. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <assert.h>
8 #include <errno.h>
9 #include <common/debug.h>
10 #include <drivers/delay_timer.h>
11 #include <lib/mmio.h>
12 
13 #include "n5x_clock_manager.h"
14 #include "n5x_system_manager.h"
15 
16 
17 
clk_get_pll_output_hz(void)18 uint64_t clk_get_pll_output_hz(void)
19 {
20 	uint32_t clksrc;
21 	uint32_t scr_reg;
22 	uint32_t divf;
23 	uint32_t divr;
24 	uint32_t divq;
25 	uint32_t power = 1;
26 	uint64_t clock = 0;
27 
28 	clksrc = ((get_clk_freq(CLKMGR_PERPLL_PLLGLOB)) &
29 			CLKMGR_PLLGLOB_VCO_PSRC_MASK) >> CLKMGR_PLLGLOB_VCO_PSRC_OFFSET;
30 
31 	switch (clksrc) {
32 	case CLKMGR_VCO_PSRC_EOSC1:
33 		scr_reg = SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_1);
34 		clock = mmio_read_32(scr_reg);
35 		break;
36 
37 	case CLKMGR_VCO_PSRC_INTOSC:
38 		clock = CLKMGR_INTOSC_HZ;
39 		break;
40 
41 	case CLKMGR_VCO_PSRC_F2S:
42 		scr_reg = SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_2);
43 		clock = mmio_read_32(scr_reg);
44 		break;
45 	}
46 
47 	divf = ((get_clk_freq(CLKMGR_PERPLL_PLLDIV)) &
48 			CLKMGR_PLLDIV_FDIV_MASK) >> CLKMGR_PLLDIV_FDIV_OFFSET;
49 	divr = ((get_clk_freq(CLKMGR_PERPLL_PLLDIV)) &
50 			CLKMGR_PLLDIV_REFCLKDIV_MASK) >> CLKMGR_PLLDIV_REFCLKDIV_OFFSET;
51 	divq = ((get_clk_freq(CLKMGR_PERPLL_PLLDIV)) &
52 			CLKMGR_PLLDIV_OUTDIV_QDIV_MASK) >> CLKMGR_PLLDIV_OUTDIV_QDIV_OFFSET;
53 
54 	while (divq) {
55 		power *= 2;
56 		divq--;
57 	}
58 
59 	return ((clock * 2 * (divf + 1)) / ((divr + 1) * power));
60 }
61 
get_l4_clk(void)62 uint64_t get_l4_clk(void)
63 {
64 	uint32_t clock = 0;
65 	uint32_t mainpll_c1cnt;
66 	uint32_t perpll_c1cnt;
67 	uint32_t clksrc;
68 
69 	mainpll_c1cnt = ((get_clk_freq(CLKMGR_MAINPLL_PLLOUTDIV)) &
70 			CLKMGR_PLLOUTDIV_C1CNT_MASK) >> CLKMGR_PLLOUTDIV_C1CNT_OFFSET;
71 
72 	perpll_c1cnt = ((get_clk_freq(CLKMGR_PERPLL_PLLOUTDIV)) &
73 			CLKMGR_PLLOUTDIV_C1CNT_MASK) >> CLKMGR_PLLOUTDIV_C1CNT_OFFSET;
74 
75 	clksrc = ((get_clk_freq(CLKMGR_MAINPLL_NOCCLK)) & CLKMGR_CLKSRC_MASK) >>
76 			CLKMGR_CLKSRC_OFFSET;
77 
78 	switch (clksrc) {
79 	case CLKMGR_CLKSRC_MAIN:
80 		clock = clk_get_pll_output_hz();
81 		clock /= 1 + mainpll_c1cnt;
82 		break;
83 
84 	case CLKMGR_CLKSRC_PER:
85 		clock = clk_get_pll_output_hz();
86 		clock /= 1 + perpll_c1cnt;
87 		break;
88 
89 	default:
90 		return 0;
91 		break;
92 	}
93 
94 	clock /= BIT(((get_clk_freq(CLKMGR_MAINPLL_NOCDIV)) >>
95 			CLKMGR_NOCDIV_L4MAIN_OFFSET) & CLKMGR_NOCDIV_DIVIDER_MASK);
96 
97 	return clock;
98 }
99 
100 /* Return MPU clock */
get_mpu_clk(void)101 uint32_t get_mpu_clk(void)
102 {
103 	uint32_t clock = 0;
104 	uint32_t mainpll_c0cnt;
105 	uint32_t perpll_c0cnt;
106 	uint32_t clksrc;
107 
108 	mainpll_c0cnt = ((get_clk_freq(CLKMGR_MAINPLL_PLLOUTDIV)) &
109 			CLKMGR_PLLOUTDIV_C0CNT_MASK) >> CLKMGR_PLLOUTDIV_C0CNT_OFFSET;
110 
111 	perpll_c0cnt = ((get_clk_freq(CLKMGR_PERPLL_PLLOUTDIV)) &
112 			CLKMGR_PLLOUTDIV_C0CNT_MASK) >> CLKMGR_PLLOUTDIV_C0CNT_OFFSET;
113 
114 	clksrc = ((get_clk_freq(CLKMGR_MAINPLL_NOCCLK)) & CLKMGR_CLKSRC_MASK) >>
115 			CLKMGR_CLKSRC_OFFSET;
116 
117 	switch (clksrc) {
118 	case CLKMGR_CLKSRC_MAIN:
119 		clock = clk_get_pll_output_hz();
120 		clock /= 1 + mainpll_c0cnt;
121 		break;
122 
123 	case CLKMGR_CLKSRC_PER:
124 		clock = clk_get_pll_output_hz();
125 		clock /= 1 + perpll_c0cnt;
126 		break;
127 
128 	default:
129 		return 0;
130 		break;
131 	}
132 
133 	clock /= BIT(((get_clk_freq(CLKMGR_MAINPLL_NOCDIV)) >>
134 			CLKMGR_NOCDIV_L4MAIN_OFFSET) & CLKMGR_NOCDIV_DIVIDER_MASK);
135 
136 	return clock;
137 }
138 
139 /* Calculate clock frequency based on parameter */
get_clk_freq(uint32_t psrc_reg)140 uint32_t get_clk_freq(uint32_t psrc_reg)
141 {
142 	uint32_t clk_psrc;
143 
144 	clk_psrc = mmio_read_32(CLKMGR_N5X_BASE + psrc_reg);
145 
146 	return clk_psrc;
147 }
148 
149 /* Get cpu freq clock */
get_cpu_clk(void)150 uint32_t get_cpu_clk(void)
151 {
152 	uint32_t cpu_clk = 0;
153 
154 	cpu_clk = get_mpu_clk()/PLAT_HZ_CONVERT_TO_MHZ;
155 
156 	return cpu_clk;
157 }
158