1 /*
2 * Copyright (c) 2022-2024, Intel Corporation.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include <zephyr/logging/log.h>
9 #include <zephyr/arch/cpu.h>
10 #include <socfpga_system_manager.h>
11 #include <zephyr/sys/__assert.h>
12
13 #include "clock_control_agilex5_ll.h"
14
15 LOG_MODULE_REGISTER(clock_control_agilex5_ll, CONFIG_CLOCK_CONTROL_LOG_LEVEL);
16
17 /* Extract reference clock from platform clock source */
get_ref_clk(mm_reg_t pllglob_reg,mm_reg_t pllm_reg)18 static uint32_t get_ref_clk(mm_reg_t pllglob_reg, mm_reg_t pllm_reg)
19 {
20 uint32_t arefclkdiv = 0U;
21 uint32_t ref_clk = 0U;
22 uint32_t mdiv = 0U;
23 uint32_t pllglob_val = 0U;
24 uint32_t pllm_val = 0U;
25
26 /* Read pllglob and pllm registers */
27 pllglob_val = sys_read32(pllglob_reg);
28 pllm_val = sys_read32(pllm_reg);
29
30 /*
31 * Based on the clock source, read the values from System Manager boot
32 * scratch registers. These values are filled by boot loader based on
33 * hand-off data.
34 */
35 switch (CLKCTRL_PSRC(pllglob_val)) {
36 case CLKCTRL_PLLGLOB_PSRC_EOSC1:
37 ref_clk = sys_read32(SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_1));
38 break;
39
40 case CLKCTRL_PLLGLOB_PSRC_INTOSC:
41 ref_clk = CLKCTRL_INTOSC_HZ;
42 break;
43
44 case CLKCTRL_PLLGLOB_PSRC_F2S:
45 ref_clk = sys_read32(SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_2));
46 break;
47
48 default:
49 ref_clk = 0;
50 __ASSERT(0, "Invalid input clock source");
51 break;
52 }
53
54 /* Get reference clock divider */
55 arefclkdiv = CLKCTRL_PLLGLOB_AREFCLKDIV(pllglob_val);
56 __ASSERT(arefclkdiv != 0, "Reference clock divider is zero");
57 ref_clk /= arefclkdiv;
58
59 /* Feedback clock divider */
60 mdiv = CLKCTRL_PLLM_MDIV(pllm_val);
61 ref_clk *= mdiv;
62
63 LOG_DBG("%s: ref_clk %u\n", __func__, ref_clk);
64
65 return ref_clk;
66 }
67
68 /* Calculate clock frequency based on parameter */
get_clk_freq(mm_reg_t psrc_reg,mm_reg_t mainpllc_reg,mm_reg_t perpllc_reg)69 static uint32_t get_clk_freq(mm_reg_t psrc_reg, mm_reg_t mainpllc_reg,
70 mm_reg_t perpllc_reg)
71 {
72 uint32_t clock_val = 0U;
73 uint32_t clk_psrc = 0U;
74 uint32_t pllcx_div = 0U;
75
76 /*
77 * Select source for the active 5:1 clock selection when the PLL
78 * is not bypassed
79 */
80 clk_psrc = sys_read32(psrc_reg);
81 switch (GET_CLKCTRL_CLKSRC(clk_psrc)) {
82 case CLKCTRL_CLKSRC_MAIN:
83 clock_val = get_ref_clk(CLKCTRL_MAINPLL(PLLGLOB), CLKCTRL_MAINPLL(PLLM));
84 pllcx_div = (sys_read32(mainpllc_reg) & CLKCTRL_PLLCX_DIV_MSK);
85 __ASSERT(pllcx_div != 0, "Main PLLC clock divider is zero");
86 clock_val /= pllcx_div;
87 break;
88
89 case CLKCTRL_CLKSRC_PER:
90 clock_val = get_ref_clk(CLKCTRL_PERPLL(PLLGLOB), CLKCTRL_PERPLL(PLLM));
91 pllcx_div = (sys_read32(perpllc_reg) & CLKCTRL_PLLCX_DIV_MSK);
92 __ASSERT(pllcx_div != 0, "Peripheral PLLC clock divider is zero");
93 clock_val /= pllcx_div;
94 break;
95
96 case CLKCTRL_CLKSRC_OSC1:
97 clock_val = sys_read32(SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_1));
98 break;
99
100 case CLKCTRL_CLKSRC_INTOSC:
101 clock_val = CLKCTRL_INTOSC_HZ;
102 break;
103
104 case CLKCTRL_CLKSRC_FPGA:
105 clock_val = sys_read32(SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_2));
106 break;
107
108 default:
109 __ASSERT(0, "Invalid clock source select");
110 break;
111 }
112
113 LOG_DBG("%s: clock source %lu and its value %u\n",
114 __func__, GET_CLKCTRL_CLKSRC(clk_psrc), clock_val);
115
116 return clock_val;
117 }
118
119 /* Get L3 free clock */
get_l3_main_free_clk(void)120 static uint32_t get_l3_main_free_clk(void)
121 {
122 return get_clk_freq(CLKCTRL_MAINPLL(NOCCLK),
123 CLKCTRL_MAINPLL(PLLC3),
124 CLKCTRL_PERPLL(PLLC1));
125 }
126
127 /* Get L4 mp clock */
get_l4_mp_clk(void)128 static uint32_t get_l4_mp_clk(void)
129 {
130 uint32_t l3_main_free_clk = get_l3_main_free_clk();
131 uint32_t mainpll_nocdiv_l4mp = BIT(GET_CLKCTRL_MAINPLL_NOCDIV_L4MP(
132 sys_read32(CLKCTRL_MAINPLL(NOCDIV))));
133
134 uint32_t l4_mp_clk = (l3_main_free_clk / mainpll_nocdiv_l4mp);
135
136 return l4_mp_clk;
137 }
138
139 /*
140 * Get L4 sp clock.
141 * "l4_sp_clk" (100MHz) will be used for slow peripherals like UART, I2C,
142 * Timers ...etc.
143 */
get_l4_sp_clk(void)144 static uint32_t get_l4_sp_clk(void)
145 {
146 uint32_t l3_main_free_clk = get_l3_main_free_clk();
147 uint32_t mainpll_nocdiv_l4sp = BIT(GET_CLKCTRL_MAINPLL_NOCDIV_L4SP(
148 sys_read32(CLKCTRL_MAINPLL(NOCDIV))));
149
150 uint32_t l4_sp_clk = (l3_main_free_clk / mainpll_nocdiv_l4sp);
151
152 return l4_sp_clk;
153 }
154
155 /* Get MPU clock */
get_mpu_clk(void)156 uint32_t get_mpu_clk(void)
157 {
158 uint8_t cpu_id = arch_curr_cpu()->id;
159 uint32_t ctr_reg = 0U;
160 uint32_t clock_val = 0U;
161
162 if (cpu_id > CLKCTRL_CPU_ID_CORE1) {
163 clock_val = get_clk_freq(CLKCTRL_CTLGRP(CORE23CTR),
164 CLKCTRL_MAINPLL(PLLC0),
165 CLKCTRL_PERPLL(PLLC0));
166 } else {
167 clock_val = get_clk_freq(CLKCTRL_CTLGRP(CORE01CTR),
168 CLKCTRL_MAINPLL(PLLC1),
169 CLKCTRL_PERPLL(PLLC0));
170 }
171
172 switch (cpu_id) {
173 case CLKCTRL_CPU_ID_CORE0:
174 case CLKCTRL_CPU_ID_CORE1:
175 ctr_reg = CLKCTRL_CTLGRP(CORE01CTR);
176 break;
177
178 case CLKCTRL_CPU_ID_CORE2:
179 ctr_reg = CLKCTRL_CTLGRP(CORE2CTR);
180 break;
181
182 case CLKCTRL_CPU_ID_CORE3:
183 ctr_reg = CLKCTRL_CTLGRP(CORE3CTR);
184 break;
185
186 default:
187 break;
188 }
189
190 /* Division setting for ping pong counter in clock slice */
191 clock_val /= 1 + (sys_read32(ctr_reg) & CLKCTRL_PLLCX_DIV_MSK);
192
193 return clock_val;
194 }
195
196 /* Calculate clock frequency to be used for watchdog timer */
get_wdt_clk(void)197 uint32_t get_wdt_clk(void)
198 {
199 uint32_t l3_main_free_clk = get_l3_main_free_clk();
200 uint32_t mainpll_nocdiv_l4sysfreeclk = BIT(GET_CLKCTRL_MAINPLL_NOCDIV_L4SYSFREE(
201 sys_read32(CLKCTRL_MAINPLL(NOCDIV))));
202 uint32_t l4_sys_free_clk = (l3_main_free_clk / mainpll_nocdiv_l4sysfreeclk);
203
204 return l4_sys_free_clk;
205 }
206
207 /* Get clock frequency to be used for UART driver */
get_uart_clk(void)208 uint32_t get_uart_clk(void)
209 {
210 return get_l4_sp_clk();
211 }
212
213 /* Calculate clock frequency to be used for SDMMC driver */
get_sdmmc_clk(void)214 uint32_t get_sdmmc_clk(void)
215 {
216 uint32_t l4_mp_clk = get_l4_mp_clk();
217 uint32_t mainpll_nocdiv = sys_read32(CLKCTRL_MAINPLL(NOCDIV));
218 uint32_t sdmmc_clk = l4_mp_clk / BIT(GET_CLKCTRL_MAINPLL_NOCDIV_SPHY(mainpll_nocdiv));
219
220 return sdmmc_clk;
221 }
222
223 /* Calculate clock frequency to be used for Timer driver */
get_timer_clk(void)224 uint32_t get_timer_clk(void)
225 {
226 return get_l4_sp_clk();
227 }
228
229 /* Calculate clock frequency to be used for QSPI driver */
get_qspi_clk(void)230 uint32_t get_qspi_clk(void)
231 {
232 uint32_t scr_reg, ref_clk;
233
234 scr_reg = SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_0);
235 ref_clk = sys_read32(scr_reg);
236
237 /*
238 * In ATF, the qspi clock is divided by 1000 and loaded in scratch cold register 0
239 * So in Zephyr, reverting back the clock frequency by multiplying by 1000.
240 */
241 return (ref_clk * 1000);
242 }
243
244 /* Calculate clock frequency to be used for I2C driver */
get_i2c_clk(void)245 uint32_t get_i2c_clk(void)
246 {
247 return get_l4_sp_clk();
248 }
249
250 /* Calculate clock frequency to be used for I3C driver */
get_i3c_clk(void)251 uint32_t get_i3c_clk(void)
252 {
253 return get_l4_mp_clk();
254 }
255