1 /*
2 * Copyright (c) 2021-2023 HPMicro
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7 #include "hpm_clock_drv.h"
8 #include "hpm_sysctl_drv.h"
9 #include "hpm_soc.h"
10 #include "hpm_common.h"
11 #include "hpm_pllctlv2_drv.h"
12 /***********************************************************************************************************************
13 * Definitions
14 **********************************************************************************************************************/
15
16 /* Clock preset values */
17 #define FREQ_PRESET1_OSC0_CLK0 (24000000UL)
18 #define FREQ_PRESET1_PLL0_CLK0 (720000000UL)
19 #define FREQ_PRESET1_PLL0_CLK1 (600000000UL)
20 #define FREQ_PRESET1_PLL0_CLK2 (400000000UL)
21 #define FREQ_PRESET1_PLL1_CLK0 (800000000UL)
22 #define FREQ_PRESET1_PLL1_CLK1 (666000000UL)
23 #define FREQ_PRESET1_PLL1_CLK2 (500000000UL)
24 #define FREQ_PRESET1_PLL1_CLK3 (266000000UL)
25 #define FREQ_32KHz (32768UL)
26 #define ADC_INSTANCE_NUM ARRAY_SIZE(HPM_SYSCTL->ADCCLK)
27 #define DAC_INSTANCE_NUM ARRAY_SIZE(HPM_SYSCTL->DACCLK)
28 #define WDG_INSTANCE_NUM (2U)
29 #define BUS_FREQ_MAX (200000000UL)
30 #define FREQ_1MHz (1000000UL)
31
32 /* Clock On/Off definitions */
33 #define CLOCK_ON (true)
34 #define CLOCK_OFF (false)
35
36
37 /***********************************************************************************************************************
38 * Prototypes
39 **********************************************************************************************************************/
40
41 /**
42 * @brief Get Clock frequency for IP in common group
43 */
44 static uint32_t get_frequency_for_ip_in_common_group(clock_node_t node);
45
46 /**
47 * @brief Get Clock frequency for ADC
48 */
49 static uint32_t get_frequency_for_adc(uint32_t clk_src_type, uint32_t instance);
50
51 /**
52 * @brief Get Clock frequency for WDG
53 */
54 static uint32_t get_frequency_for_wdg(uint32_t instance);
55
56 /**
57 * @brief Get Clock frequency for PWDG
58 */
59 static uint32_t get_frequency_for_pwdg(void);
60
61 /**
62 * @brief Turn on/off the IP clock
63 */
64 static void switch_ip_clock(clock_name_t clock_name, bool on);
65
66 static uint32_t get_frequency_for_cpu(void);
67 static uint32_t get_frequency_for_ahb(void);
68
69
70 /***********************************************************************************************************************
71 * Variables
72 **********************************************************************************************************************/
73 static const clock_node_t s_adc_clk_mux_node[] = {
74 clock_node_ahb,
75 clock_node_ana0
76 };
77
78 static EWDG_Type *const s_wdgs[] = { HPM_WDG0, HPM_WDG1};
79
80 uint32_t hpm_core_clock;
81
82
83 /***********************************************************************************************************************
84 * Codes
85 **********************************************************************************************************************/
clock_get_frequency(clock_name_t clock_name)86 uint32_t clock_get_frequency(clock_name_t clock_name)
87 {
88 uint32_t clk_freq = 0UL;
89 uint32_t clk_src_type = GET_CLK_SRC_GROUP_FROM_NAME(clock_name);
90 uint32_t node_or_instance = GET_CLK_NODE_FROM_NAME(clock_name);
91 switch (clk_src_type) {
92 case CLK_SRC_GROUP_COMMON:
93 clk_freq = get_frequency_for_ip_in_common_group((clock_node_t) node_or_instance);
94 break;
95 case CLK_SRC_GROUP_ADC:
96 clk_freq = get_frequency_for_adc(CLK_SRC_GROUP_ADC, node_or_instance);
97 break;
98 case CLK_SRC_GROUP_WDG:
99 clk_freq = get_frequency_for_wdg(node_or_instance);
100 break;
101 case CLK_SRC_GROUP_PWDG:
102 clk_freq = get_frequency_for_pwdg();
103 break;
104 case CLK_SRC_GROUP_PMIC:
105 clk_freq = FREQ_PRESET1_OSC0_CLK0;
106 break;
107 case CLK_SRC_GROUP_CPU0:
108 clk_freq = get_frequency_for_cpu();
109 break;
110 case CLK_SRC_GROUP_AHB:
111 clk_freq = get_frequency_for_ahb();
112 break;
113 case CLK_SRC_GROUP_SRC:
114 clk_freq = get_frequency_for_source((clock_source_t) node_or_instance);
115 break;
116 default:
117 clk_freq = 0UL;
118 break;
119 }
120 return clk_freq;
121 }
122
get_frequency_for_source(clock_source_t source)123 uint32_t get_frequency_for_source(clock_source_t source)
124 {
125 uint32_t clk_freq = 0UL;
126 switch (source) {
127 case clock_source_osc0_clk0:
128 clk_freq = FREQ_PRESET1_OSC0_CLK0;
129 break;
130 case clock_source_pll0_clk0:
131 clk_freq = pllctlv2_get_pll_postdiv_freq_in_hz(HPM_PLLCTLV2, 0U, 0U);
132 break;
133 case clock_source_pll0_clk1:
134 clk_freq = pllctlv2_get_pll_postdiv_freq_in_hz(HPM_PLLCTLV2, 0U, 1U);
135 break;
136 case clock_source_pll0_clk2:
137 clk_freq = pllctlv2_get_pll_postdiv_freq_in_hz(HPM_PLLCTLV2, 0U, 2U);
138 break;
139 case clock_source_pll1_clk0:
140 clk_freq = pllctlv2_get_pll_postdiv_freq_in_hz(HPM_PLLCTLV2, 1U, 0U);
141 break;
142 case clock_source_pll1_clk1:
143 clk_freq = pllctlv2_get_pll_postdiv_freq_in_hz(HPM_PLLCTLV2, 1U, 1U);
144 break;
145 case clock_source_pll1_clk2:
146 clk_freq = pllctlv2_get_pll_postdiv_freq_in_hz(HPM_PLLCTLV2, 1U, 2U);
147 break;
148 case clock_source_pll1_clk3:
149 clk_freq = pllctlv2_get_pll_postdiv_freq_in_hz(HPM_PLLCTLV2, 1U, 3U);
150 break;
151 default:
152 clk_freq = 0UL;
153 break;
154 }
155
156 return clk_freq;
157 }
158
get_frequency_for_ip_in_common_group(clock_node_t node)159 static uint32_t get_frequency_for_ip_in_common_group(clock_node_t node)
160 {
161 uint32_t clk_freq = 0UL;
162 uint32_t node_or_instance = GET_CLK_NODE_FROM_NAME(node);
163
164 if (node_or_instance < clock_node_end) {
165 uint32_t clk_node = (uint32_t) node_or_instance;
166
167 uint32_t clk_div = 1UL + SYSCTL_CLOCK_DIV_GET(HPM_SYSCTL->CLOCK[clk_node]);
168 clock_source_t clk_mux = (clock_source_t) SYSCTL_CLOCK_MUX_GET(HPM_SYSCTL->CLOCK[clk_node]);
169 clk_freq = get_frequency_for_source(clk_mux) / clk_div;
170 }
171 return clk_freq;
172 }
173
get_frequency_for_adc(uint32_t clk_src_type,uint32_t instance)174 static uint32_t get_frequency_for_adc(uint32_t clk_src_type, uint32_t instance)
175 {
176 uint32_t clk_freq = 0UL;
177 bool is_mux_valid = false;
178 clock_node_t node = clock_node_end;
179 uint32_t adc_index = instance;
180
181 (void) clk_src_type;
182
183 if (adc_index < ADC_INSTANCE_NUM) {
184 uint32_t mux_in_reg = SYSCTL_ADCCLK_MUX_GET(HPM_SYSCTL->ADCCLK[adc_index]);
185 if (mux_in_reg < ARRAY_SIZE(s_adc_clk_mux_node)) {
186 node = s_adc_clk_mux_node[mux_in_reg];
187 is_mux_valid = true;
188 }
189 }
190
191 if (is_mux_valid) {
192 if (node != clock_node_ahb) {
193 node += instance;
194 clk_freq = get_frequency_for_ip_in_common_group(node);
195 } else {
196 clk_freq = get_frequency_for_ahb();
197 }
198 }
199 return clk_freq;
200 }
201
get_frequency_for_wdg(uint32_t instance)202 static uint32_t get_frequency_for_wdg(uint32_t instance)
203 {
204 uint32_t freq_in_hz;
205 if (EWDG_CTRL0_CLK_SEL_GET(s_wdgs[instance]->CTRL0) == 0) {
206 freq_in_hz = get_frequency_for_ahb();
207 } else {
208 freq_in_hz = FREQ_32KHz;
209 }
210
211 return freq_in_hz;
212 }
213
get_frequency_for_pwdg(void)214 static uint32_t get_frequency_for_pwdg(void)
215 {
216 uint32_t freq_in_hz;
217 if (EWDG_CTRL0_CLK_SEL_GET(HPM_PWDG->CTRL0) == 0) {
218 freq_in_hz = FREQ_PRESET1_OSC0_CLK0;
219 } else {
220 freq_in_hz = FREQ_32KHz;
221 }
222
223 return freq_in_hz;
224 }
225
get_frequency_for_cpu(void)226 static uint32_t get_frequency_for_cpu(void)
227 {
228 uint32_t mux = SYSCTL_CLOCK_CPU_MUX_GET(HPM_SYSCTL->CLOCK_CPU[0]);
229 uint32_t div = SYSCTL_CLOCK_CPU_DIV_GET(HPM_SYSCTL->CLOCK_CPU[0]) + 1U;
230 return (get_frequency_for_source(mux) / div);
231 }
232
get_frequency_for_ahb(void)233 static uint32_t get_frequency_for_ahb(void)
234 {
235 uint32_t div = SYSCTL_CLOCK_CPU_SUB0_DIV_GET(HPM_SYSCTL->CLOCK_CPU[0]) + 1U;
236 return (get_frequency_for_cpu() / div);
237 }
238
clock_get_source(clock_name_t clock_name)239 clk_src_t clock_get_source(clock_name_t clock_name)
240 {
241 uint8_t clk_src_group = CLK_SRC_GROUP_INVALID;
242 uint8_t clk_src_index = 0xFU;
243 uint32_t clk_src_type = GET_CLK_SRC_GROUP_FROM_NAME(clock_name);
244 uint32_t node_or_instance = GET_CLK_NODE_FROM_NAME(clock_name);
245 switch (clk_src_type) {
246 case CLK_SRC_GROUP_COMMON:
247 clk_src_group = CLK_SRC_GROUP_COMMON;
248 clk_src_index = SYSCTL_CLOCK_MUX_GET(HPM_SYSCTL->CLOCK[node_or_instance]);
249 break;
250 case CLK_SRC_GROUP_ADC:
251 if (node_or_instance < ADC_INSTANCE_NUM) {
252 clk_src_group = CLK_SRC_GROUP_ADC;
253 clk_src_index = SYSCTL_ADCCLK_MUX_GET(HPM_SYSCTL->ADCCLK[node_or_instance]);
254 }
255 break;
256 case CLK_SRC_GROUP_WDG:
257 if (node_or_instance < WDG_INSTANCE_NUM) {
258 clk_src_group = CLK_SRC_GROUP_WDG;
259 clk_src_index = EWDG_CTRL0_CLK_SEL_GET(s_wdgs[node_or_instance]->CTRL0);
260 }
261 break;
262 case CLK_SRC_GROUP_PWDG:
263 clk_src_group = CLK_SRC_GROUP_PWDG;
264 clk_src_index = EWDG_CTRL0_CLK_SEL_GET(HPM_PWDG->CTRL0);
265 break;
266 case CLK_SRC_GROUP_PMIC:
267 clk_src_group = CLK_SRC_GROUP_COMMON;
268 clk_src_index = clock_source_osc0_clk0;
269 break;
270 case CLK_SRC_GROUP_CPU0:
271 case CLK_SRC_GROUP_AHB:
272 clk_src_group = CLK_SRC_GROUP_CPU0;
273 clk_src_index = SYSCTL_CLOCK_CPU_MUX_GET(HPM_SYSCTL->CLOCK_CPU[0]);
274 break;
275 case CLK_SRC_GROUP_SRC:
276 clk_src_index = (clk_src_t) node_or_instance;
277 break;
278 default:
279 clk_src_group = CLK_SRC_GROUP_INVALID;
280 break;
281 }
282
283 clk_src_t clk_src;
284 if (clk_src_group != CLK_SRC_GROUP_INVALID) {
285 clk_src = MAKE_CLK_SRC(clk_src_group, clk_src_index);
286 } else {
287 clk_src = clk_src_invalid;
288 }
289
290 return clk_src;
291 }
292
clock_set_adc_source(clock_name_t clock_name,clk_src_t src)293 hpm_stat_t clock_set_adc_source(clock_name_t clock_name, clk_src_t src)
294 {
295 uint32_t clk_src_type = GET_CLK_SRC_GROUP_FROM_NAME(clock_name);
296 uint32_t node_or_instance = GET_CLK_NODE_FROM_NAME(clock_name);
297
298 if ((clk_src_type != CLK_SRC_GROUP_ADC) || (node_or_instance >= ADC_INSTANCE_NUM)) {
299 return status_clk_invalid;
300 }
301
302 if ((src < clk_adc_src_ahb0) || (src > clk_adc_src_ana1)) {
303 return status_clk_src_invalid;
304 }
305
306 uint32_t clk_src_index = GET_CLK_SRC_INDEX(src);
307 HPM_SYSCTL->ADCCLK[node_or_instance] =
308 (HPM_SYSCTL->ADCCLK[node_or_instance] & ~SYSCTL_ADCCLK_MUX_MASK) | SYSCTL_ADCCLK_MUX_SET(clk_src_index);
309
310 return status_success;
311 }
312
clock_set_source_divider(clock_name_t clock_name,clk_src_t src,uint32_t div)313 hpm_stat_t clock_set_source_divider(clock_name_t clock_name, clk_src_t src, uint32_t div)
314 {
315 hpm_stat_t status = status_success;
316 uint32_t clk_src_type = GET_CLK_SRC_GROUP_FROM_NAME(clock_name);
317 uint32_t node_or_instance = GET_CLK_NODE_FROM_NAME(clock_name);
318 switch (clk_src_type) {
319 case CLK_SRC_GROUP_COMMON:
320 if ((div < 1U) || (div > 256U)) {
321 status = status_clk_div_invalid;
322 } else {
323 clock_source_t clk_src = GET_CLOCK_SOURCE_FROM_CLK_SRC(src);
324 sysctl_config_clock(HPM_SYSCTL, (clock_node_t) node_or_instance, clk_src, div);
325 }
326 break;
327 case CLK_SRC_GROUP_ADC:
328 case CLK_SRC_GROUP_WDG:
329 case CLK_SRC_GROUP_PWDG:
330 case CLK_SRC_GROUP_SRC:
331 status = status_clk_operation_unsupported;
332 break;
333 case CLK_SRC_GROUP_PMIC:
334 status = status_clk_fixed;
335 break;
336 case CLK_SRC_GROUP_AHB:
337 status = status_clk_shared_cpu0;
338 break;
339 case CLK_SRC_GROUP_CPU0:
340 if (node_or_instance == clock_node_cpu0) {
341 /* Note: the AXI and AHB BUS share the same CPU clock, once the CPU clock frequency
342 * changes, the AXI and AHB clock changes accordingly, here the driver ensures the
343 * AXI and AHB bus clock frequency is in valid range.
344 */
345 uint32_t expected_freq = get_frequency_for_source((clock_source_t) src) / div;
346 uint32_t ahb_sub_div = (expected_freq + BUS_FREQ_MAX - 1U) / BUS_FREQ_MAX;
347 sysctl_config_cpu0_domain_clock(HPM_SYSCTL, (clock_source_t) src, div, ahb_sub_div);
348 } else {
349 status = status_clk_shared_cpu0;
350 }
351 break;
352 default:
353 status = status_clk_src_invalid;
354 break;
355 }
356
357 return status;
358 }
359
switch_ip_clock(clock_name_t clock_name,bool on)360 static void switch_ip_clock(clock_name_t clock_name, bool on)
361 {
362 uint32_t resource = GET_CLK_RESOURCE_FROM_NAME(clock_name);
363
364 if (resource < sysctl_resource_end) {
365 uint32_t mode = on ? 1UL : 2UL;
366 HPM_SYSCTL->RESOURCE[resource] =
367 (HPM_SYSCTL->RESOURCE[resource] & ~SYSCTL_RESOURCE_MODE_MASK) | SYSCTL_RESOURCE_MODE_SET(mode);
368 }
369 }
370
371
clock_enable(clock_name_t clock_name)372 void clock_enable(clock_name_t clock_name)
373 {
374 switch_ip_clock(clock_name, CLOCK_ON);
375 }
376
clock_disable(clock_name_t clock_name)377 void clock_disable(clock_name_t clock_name)
378 {
379 switch_ip_clock(clock_name, CLOCK_OFF);
380 }
381
clock_add_to_group(clock_name_t clock_name,uint32_t group)382 void clock_add_to_group(clock_name_t clock_name, uint32_t group)
383 {
384 uint32_t resource = GET_CLK_RESOURCE_FROM_NAME(clock_name);
385
386 if (resource < sysctl_resource_end) {
387 sysctl_enable_group_resource(HPM_SYSCTL, group, resource, true);
388 }
389 }
390
clock_remove_from_group(clock_name_t clock_name,uint32_t group)391 void clock_remove_from_group(clock_name_t clock_name, uint32_t group)
392 {
393 uint32_t resource = GET_CLK_RESOURCE_FROM_NAME(clock_name);
394
395 if (resource < sysctl_resource_end) {
396 sysctl_enable_group_resource(HPM_SYSCTL, group, resource, false);
397 }
398 }
399
clock_check_in_group(clock_name_t clock_name,uint32_t group)400 bool clock_check_in_group(clock_name_t clock_name, uint32_t group)
401 {
402 uint32_t resource = GET_CLK_RESOURCE_FROM_NAME(clock_name);
403
404 return sysctl_check_group_resource_enable(HPM_SYSCTL, group, resource);
405 }
406
clock_connect_group_to_cpu(uint32_t group,uint32_t cpu)407 void clock_connect_group_to_cpu(uint32_t group, uint32_t cpu)
408 {
409 if (cpu == 0U) {
410 HPM_SYSCTL->AFFILIATE[cpu].SET = (1UL << group);
411 }
412 }
413
clock_disconnect_group_from_cpu(uint32_t group,uint32_t cpu)414 void clock_disconnect_group_from_cpu(uint32_t group, uint32_t cpu)
415 {
416 if (cpu == 0U) {
417 HPM_SYSCTL->AFFILIATE[cpu].CLEAR = (1UL << group);
418 }
419 }
420
clock_cpu_delay_us(uint32_t us)421 void clock_cpu_delay_us(uint32_t us)
422 {
423 uint32_t ticks_per_us = (hpm_core_clock + FREQ_1MHz - 1U) / FREQ_1MHz;
424 uint64_t expected_ticks = hpm_csr_get_core_cycle() + ticks_per_us * us;
425 while (hpm_csr_get_core_cycle() < expected_ticks) {
426 }
427 }
428
clock_cpu_delay_ms(uint32_t ms)429 void clock_cpu_delay_ms(uint32_t ms)
430 {
431 uint32_t ticks_per_us = (hpm_core_clock + FREQ_1MHz - 1U) / FREQ_1MHz;
432 uint64_t expected_ticks = hpm_csr_get_core_cycle() + (uint64_t)ticks_per_us * 1000UL * ms;
433 while (hpm_csr_get_core_cycle() < expected_ticks) {
434 }
435 }
436
clock_update_core_clock(void)437 void clock_update_core_clock(void)
438 {
439 hpm_core_clock = clock_get_frequency(clock_cpu0);
440 }
441