1 /*
2  * Copyright (c) 2022-2024 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 (400000000UL)
19 #define FREQ_PRESET1_PLL0_CLK1 (333333333UL)
20 #define FREQ_PRESET1_PLL1_CLK2 (250000000UL)
21 #define FREQ_PRESET1_PLL1_CLK0 (480000000UL)
22 #define FREQ_PRESET1_PLL1_CLK1 (320000000UL)
23 #define FREQ_PRESET1_PLL2_CLK0 (516096000UL)
24 #define FREQ_PRESET1_PLL2_CLK1 (451584000UL)
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 
43 /**
44  * @brief Get Clock frequency for IP in common group
45  */
46 static uint32_t get_frequency_for_ip_in_common_group(clock_node_t node);
47 
48 /**
49  * @brief Get Clock frequency for ADC
50  */
51 static uint32_t get_frequency_for_adc(uint32_t clk_src_type, uint32_t instance);
52 
53 /**
54  * @brief Get Clock frequency for DAC
55  */
56 static uint32_t get_frequency_for_dac(uint32_t instance);
57 
58 /**
59  * @brief Get Clock frequency for WDG
60  */
61 static uint32_t get_frequency_for_wdg(uint32_t instance);
62 
63 /**
64  * @brief Get Clock frequency for PWDG
65  */
66 static uint32_t get_frequency_for_pwdg(void);
67 
68 /**
69  * @brief Turn on/off the IP clock
70  */
71 static void switch_ip_clock(clock_name_t clock_name, bool on);
72 
73 static uint32_t get_frequency_for_cpu(void);
74 static uint32_t get_frequency_for_axi(void);
75 static uint32_t get_frequency_for_ahb(void);
76 
77 /***********************************************************************************************************************
78  * Variables
79  **********************************************************************************************************************/
80 static const clock_node_t s_adc_clk_mux_node[] = {
81     clock_node_ana0, clock_node_ahb,
82 };
83 
84 static const clock_node_t s_dac_clk_mux_node[] = {
85     clock_node_ana3, clock_node_ahb
86 };
87 
88 static WDG_Type *const s_wdgs[] = { HPM_WDG0, HPM_WDG1 };
89 
90 uint32_t hpm_core_clock;
91 
92 /***********************************************************************************************************************
93  * Codes
94  **********************************************************************************************************************/
clock_get_frequency(clock_name_t clock_name)95 uint32_t clock_get_frequency(clock_name_t clock_name)
96 {
97     uint32_t clk_freq;
98     uint32_t clk_src_type = GET_CLK_SRC_GROUP_FROM_NAME(clock_name);
99     uint32_t node_or_instance = GET_CLK_NODE_FROM_NAME(clock_name);
100     switch (clk_src_type) {
101     case CLK_SRC_GROUP_COMMON:
102         clk_freq = get_frequency_for_ip_in_common_group((clock_node_t) node_or_instance);
103         break;
104     case CLK_SRC_GROUP_ADC:
105         clk_freq = get_frequency_for_adc(CLK_SRC_GROUP_ADC, node_or_instance);
106         break;
107     case CLK_SRC_GROUP_DAC:
108         clk_freq = get_frequency_for_dac(node_or_instance);
109         break;
110     case CLK_SRC_GROUP_WDG:
111         clk_freq = get_frequency_for_wdg(node_or_instance);
112         break;
113     case CLK_SRC_GROUP_PWDG:
114         clk_freq = get_frequency_for_pwdg();
115         break;
116     case CLK_SRC_GROUP_PMIC:
117         clk_freq = FREQ_PRESET1_OSC0_CLK0;
118         break;
119     case CLK_SRC_GROUP_CPU0:
120         clk_freq = get_frequency_for_cpu();
121         break;
122     case CLK_SRC_GROUP_AHB:
123         clk_freq = get_frequency_for_ahb();
124         break;
125     case CLK_SRC_GROUP_AXI:
126         clk_freq = get_frequency_for_axi();
127         break;
128     case CLK_SRC_GROUP_SRC:
129         clk_freq = get_frequency_for_source((clock_source_t) node_or_instance);
130         break;
131     default:
132         clk_freq = 0UL;
133         break;
134     }
135     return clk_freq;
136 }
137 
get_frequency_for_source(clock_source_t source)138 uint32_t get_frequency_for_source(clock_source_t source)
139 {
140     uint32_t clk_freq;
141     switch (source) {
142     case clock_source_osc0_clk0:
143         clk_freq = FREQ_PRESET1_OSC0_CLK0;
144         break;
145     case clock_source_pll0_clk0:
146         clk_freq = pllctlv2_get_pll_postdiv_freq_in_hz(HPM_PLLCTLV2, 0U, 0U);
147         break;
148     case clock_source_pll0_clk1:
149         clk_freq = pllctlv2_get_pll_postdiv_freq_in_hz(HPM_PLLCTLV2, 0U, 1U);
150         break;
151     case clock_source_pll0_clk2:
152         clk_freq = pllctlv2_get_pll_postdiv_freq_in_hz(HPM_PLLCTLV2, 0U, 2U);
153         break;
154     case clock_source_pll1_clk0:
155         clk_freq = pllctlv2_get_pll_postdiv_freq_in_hz(HPM_PLLCTLV2, 1U, 0U);
156         break;
157     case clock_source_pll1_clk1:
158         clk_freq = pllctlv2_get_pll_postdiv_freq_in_hz(HPM_PLLCTLV2, 1U, 1U);
159         break;
160     case clock_source_pll2_clk0:
161         clk_freq = pllctlv2_get_pll_postdiv_freq_in_hz(HPM_PLLCTLV2, 2U, 0U);
162         break;
163     case clock_source_pll2_clk1:
164         clk_freq = pllctlv2_get_pll_postdiv_freq_in_hz(HPM_PLLCTLV2, 2U, 1U);
165         break;
166     default:
167         clk_freq = 0UL;
168         break;
169     }
170 
171     return clk_freq;
172 }
173 
get_frequency_for_ip_in_common_group(clock_node_t node)174 static uint32_t get_frequency_for_ip_in_common_group(clock_node_t node)
175 {
176     uint32_t clk_freq = 0UL;
177     uint32_t node_or_instance = GET_CLK_NODE_FROM_NAME(node);
178 
179     if (node_or_instance < clock_node_end) {
180         uint32_t clk_node = (uint32_t) node_or_instance;
181 
182         uint32_t clk_div = 1UL + SYSCTL_CLOCK_DIV_GET(HPM_SYSCTL->CLOCK[clk_node]);
183         clock_source_t clk_mux = (clock_source_t) SYSCTL_CLOCK_MUX_GET(HPM_SYSCTL->CLOCK[clk_node]);
184         clk_freq = get_frequency_for_source(clk_mux) / clk_div;
185     }
186     return clk_freq;
187 }
188 
get_frequency_for_adc(uint32_t clk_src_type,uint32_t instance)189 static uint32_t get_frequency_for_adc(uint32_t clk_src_type, uint32_t instance)
190 {
191     uint32_t clk_freq = 0UL;
192     bool is_mux_valid = false;
193     clock_node_t node = clock_node_end;
194     uint32_t adc_index = instance;
195 
196     (void) clk_src_type;
197 
198     if (adc_index < ADC_INSTANCE_NUM) {
199         uint32_t mux_in_reg = SYSCTL_ADCCLK_MUX_GET(HPM_SYSCTL->ADCCLK[adc_index]);
200         if (mux_in_reg < ARRAY_SIZE(s_adc_clk_mux_node)) {
201             node = s_adc_clk_mux_node[mux_in_reg];
202             is_mux_valid = true;
203         }
204     }
205 
206     if (is_mux_valid) {
207         if (node != clock_node_ahb) {
208             node += instance;
209             clk_freq = get_frequency_for_ip_in_common_group(node);
210         } else {
211             clk_freq = get_frequency_for_ahb();
212         }
213     }
214     return clk_freq;
215 }
216 
get_frequency_for_dac(uint32_t instance)217 static uint32_t get_frequency_for_dac(uint32_t instance)
218 {
219     uint32_t clk_freq = 0UL;
220     bool is_mux_valid = false;
221     clock_node_t node = clock_node_end;
222     if (instance < DAC_INSTANCE_NUM) {
223         uint32_t mux_in_reg = SYSCTL_DACCLK_MUX_GET(HPM_SYSCTL->DACCLK[instance]);
224         if (mux_in_reg < ARRAY_SIZE(s_dac_clk_mux_node)) {
225             node = s_dac_clk_mux_node[mux_in_reg];
226             is_mux_valid = true;
227         }
228     }
229 
230     if (is_mux_valid) {
231         if (node == clock_node_ahb) {
232             clk_freq = get_frequency_for_ahb();
233         } else {
234             node += instance;
235             clk_freq = get_frequency_for_ip_in_common_group(node);
236         }
237     }
238 
239     return clk_freq;
240 }
241 
get_frequency_for_wdg(uint32_t instance)242 static uint32_t get_frequency_for_wdg(uint32_t instance)
243 {
244     uint32_t freq_in_hz;
245     /* EXT clock is chosen */
246     if (WDG_CTRL_CLKSEL_GET(s_wdgs[instance]->CTRL) == 0) {
247         freq_in_hz = get_frequency_for_ahb();
248     }
249         /* PCLK is chosen */
250     else {
251         freq_in_hz = FREQ_32KHz;
252     }
253 
254     return freq_in_hz;
255 }
256 
get_frequency_for_pwdg(void)257 static uint32_t get_frequency_for_pwdg(void)
258 {
259     uint32_t freq_in_hz;
260     if (WDG_CTRL_CLKSEL_GET(HPM_PWDG->CTRL) == 0) {
261         freq_in_hz = FREQ_PRESET1_OSC0_CLK0;
262     } else {
263         freq_in_hz = FREQ_32KHz;
264     }
265 
266     return freq_in_hz;
267 }
268 
get_frequency_for_cpu(void)269 static uint32_t get_frequency_for_cpu(void)
270 {
271     uint32_t mux = SYSCTL_CLOCK_CPU_MUX_GET(HPM_SYSCTL->CLOCK_CPU[0]);
272     uint32_t div = SYSCTL_CLOCK_CPU_DIV_GET(HPM_SYSCTL->CLOCK_CPU[0]) + 1U;
273     return (get_frequency_for_source(mux) / div);
274 }
275 
get_frequency_for_axi(void)276 static uint32_t get_frequency_for_axi(void)
277 {
278     uint32_t div = SYSCTL_CLOCK_CPU_SUB0_DIV_GET(HPM_SYSCTL->CLOCK_CPU[0]) + 1U;
279     return (get_frequency_for_cpu() / div);
280 }
281 
get_frequency_for_ahb(void)282 static uint32_t get_frequency_for_ahb(void)
283 {
284     uint32_t div = SYSCTL_CLOCK_CPU_SUB1_DIV_GET(HPM_SYSCTL->CLOCK_CPU[0]) + 1U;
285     return (get_frequency_for_cpu() / div);
286 }
287 
clock_get_source(clock_name_t clock_name)288 clk_src_t clock_get_source(clock_name_t clock_name)
289 {
290     uint8_t clk_src_group = CLK_SRC_GROUP_INVALID;
291     uint8_t clk_src_index = 0xFU;
292     uint32_t clk_src_type = GET_CLK_SRC_GROUP_FROM_NAME(clock_name);
293     uint32_t node_or_instance = GET_CLK_NODE_FROM_NAME(clock_name);
294     switch (clk_src_type) {
295     case CLK_SRC_GROUP_COMMON:
296         clk_src_group = CLK_SRC_GROUP_COMMON;
297         clk_src_index = SYSCTL_CLOCK_MUX_GET(HPM_SYSCTL->CLOCK[node_or_instance]);
298         break;
299     case CLK_SRC_GROUP_ADC:
300         if (node_or_instance < ADC_INSTANCE_NUM) {
301             clk_src_group = CLK_SRC_GROUP_ADC;
302             clk_src_index = SYSCTL_ADCCLK_MUX_GET(HPM_SYSCTL->ADCCLK[node_or_instance]);
303         }
304         break;
305     case CLK_SRC_GROUP_DAC:
306         if (node_or_instance < DAC_INSTANCE_NUM) {
307            clk_src_group = CLK_SRC_GROUP_DAC;
308            clk_src_index = SYSCTL_DACCLK_MUX_GET(HPM_SYSCTL->DACCLK[node_or_instance]);
309         }
310         break;
311     case CLK_SRC_GROUP_WDG:
312         if (node_or_instance < WDG_INSTANCE_NUM) {
313             clk_src_group = CLK_SRC_GROUP_WDG;
314             clk_src_index = WDG_CTRL_CLKSEL_GET(s_wdgs[node_or_instance]->CTRL);
315         }
316         break;
317     case CLK_SRC_GROUP_PWDG:
318         clk_src_group = CLK_SRC_GROUP_PWDG;
319         clk_src_index = WDG_CTRL_CLKSEL_GET(HPM_PWDG->CTRL);
320         break;
321     case CLK_SRC_GROUP_PMIC:
322         clk_src_group = CLK_SRC_GROUP_COMMON;
323         clk_src_index = clock_source_osc0_clk0;
324         break;
325     case CLK_SRC_GROUP_CPU0:
326     case CLK_SRC_GROUP_AHB:
327     case CLK_SRC_GROUP_AXI:
328         clk_src_group = CLK_SRC_GROUP_CPU0;
329         clk_src_index = SYSCTL_CLOCK_CPU_MUX_GET(HPM_SYSCTL->CLOCK_CPU[0]);
330         break;
331     case CLK_SRC_GROUP_SRC:
332         clk_src_index = (clk_src_t) node_or_instance;
333         break;
334     default:
335         clk_src_group = CLK_SRC_GROUP_INVALID;
336         break;
337     }
338 
339     clk_src_t clk_src;
340     if (clk_src_group != CLK_SRC_GROUP_INVALID) {
341         clk_src = MAKE_CLK_SRC(clk_src_group, clk_src_index);
342     } else {
343         clk_src = clk_src_invalid;
344     }
345 
346     return clk_src;
347 }
348 
clock_get_divider(clock_name_t clock_name)349 uint32_t clock_get_divider(clock_name_t clock_name)
350 {
351     uint32_t clk_divider = CLOCK_DIV_INVALID;
352     uint32_t clk_src_type = GET_CLK_SRC_GROUP_FROM_NAME(clock_name);
353     uint32_t node_or_instance = GET_CLK_NODE_FROM_NAME(clock_name);
354     switch (clk_src_type) {
355     case CLK_SRC_GROUP_COMMON:
356         clk_divider = 1UL + SYSCTL_CLOCK_DIV_GET(HPM_SYSCTL->CLOCK[node_or_instance]);
357         break;
358     case CLK_SRC_GROUP_WDG:
359         if (node_or_instance < WDG_INSTANCE_NUM) {
360             clk_divider = 1UL;
361         }
362         break;
363     case CLK_SRC_GROUP_PWDG:
364         clk_divider = 1UL;
365         break;
366     case CLK_SRC_GROUP_PMIC:
367         clk_divider = 1UL;
368         break;
369     case CLK_SRC_GROUP_CPU0:
370         clk_divider = 1UL + SYSCTL_CLOCK_CPU_DIV_GET(HPM_SYSCTL->CLOCK_CPU[0]);
371         break;
372     case CLK_SRC_GROUP_AHB:
373         clk_divider = 1UL + SYSCTL_CLOCK_CPU_SUB1_DIV_GET(HPM_SYSCTL->CLOCK_CPU[0]);
374         break;
375     case CLK_SRC_GROUP_AXI:
376         clk_divider = 1UL + SYSCTL_CLOCK_CPU_SUB0_DIV_GET(HPM_SYSCTL->CLOCK_CPU[0]);
377         break;
378     default:
379         clk_divider = CLOCK_DIV_INVALID;
380         break;
381     }
382     return clk_divider;
383 }
384 
clock_set_adc_source(clock_name_t clock_name,clk_src_t src)385 hpm_stat_t clock_set_adc_source(clock_name_t clock_name, clk_src_t src)
386 {
387     uint32_t clk_src_type = GET_CLK_SRC_GROUP_FROM_NAME(clock_name);
388     uint32_t node_or_instance = GET_CLK_NODE_FROM_NAME(clock_name);
389 
390     if ((clk_src_type != CLK_SRC_GROUP_ADC) || (node_or_instance >= ADC_INSTANCE_NUM)) {
391         return status_clk_invalid;
392     }
393 
394     if ((src < clk_adc_src_ana0) || (src > clk_adc_src_ahb0)) {
395         return status_clk_src_invalid;
396     }
397 
398     uint32_t clk_src_index = GET_CLK_SRC_INDEX(src);
399     HPM_SYSCTL->ADCCLK[node_or_instance] =
400         (HPM_SYSCTL->ADCCLK[node_or_instance] & ~SYSCTL_ADCCLK_MUX_MASK) | SYSCTL_ADCCLK_MUX_SET(clk_src_index);
401 
402     return status_success;
403 }
404 
clock_set_dac_source(clock_name_t clock_name,clk_src_t src)405 hpm_stat_t clock_set_dac_source(clock_name_t clock_name, clk_src_t src)
406 {
407     uint32_t clk_src_type = GET_CLK_SRC_GROUP_FROM_NAME(clock_name);
408     uint32_t node_or_instance = GET_CLK_NODE_FROM_NAME(clock_name);
409 
410     if ((clk_src_type != CLK_SRC_GROUP_DAC) || (node_or_instance >= DAC_INSTANCE_NUM)) {
411         return status_clk_invalid;
412     }
413 
414     if ((src < clk_dac_src_ana3) || (src > clk_dac_src_ahb0)) {
415         return status_clk_src_invalid;
416     }
417 
418     uint32_t clk_src_index = GET_CLK_SRC_INDEX(src);
419     HPM_SYSCTL->DACCLK[node_or_instance] =
420         (HPM_SYSCTL->DACCLK[node_or_instance] & ~SYSCTL_DACCLK_MUX_MASK) | SYSCTL_DACCLK_MUX_SET(clk_src_index);
421 
422     return status_success;
423 }
424 
clock_set_wdg_source(clock_name_t clock_name,clk_src_t src)425 hpm_stat_t clock_set_wdg_source(clock_name_t clock_name, clk_src_t src)
426 {
427     uint32_t clk_src_grp = GET_CLK_SRC_GROUP(clock_name);
428     if ((clk_src_grp != CLK_SRC_GROUP_WDG) && (clk_src_grp != CLK_SRC_GROUP_PWDG)) {
429         return status_invalid_argument;
430     }
431     if (clock_name == clock_pwdg) {
432         if ((src == clk_pwdg_src_osc24m) || (src == clk_pwdg_src_osc32k)) {
433             uint32_t wdg_clk_src_in_ip = (uint32_t)(src - clk_pwdg_src_osc24m);
434             HPM_PWDG->CTRL = (HPM_PWDG->CTRL & ~WDG_CTRL_CLKSEL_MASK) | WDG_CTRL_CLKSEL_SET(wdg_clk_src_in_ip);
435         } else {
436             return status_invalid_argument;
437         }
438     } else {
439         uint32_t instance = GET_CLK_SRC_INDEX(clock_name);
440         if ((src == clk_wdg_src_ahb0) || (src == clk_wdg_src_osc32k)) {
441              uint32_t wdg_clk_src_in_ip = (uint32_t)(src - clk_wdg_src_ahb0);
442             s_wdgs[instance]->CTRL = (s_wdgs[instance]->CTRL & ~WDG_CTRL_CLKSEL_MASK) | WDG_CTRL_CLKSEL_SET(wdg_clk_src_in_ip);
443         } else {
444             return status_invalid_argument;
445         }
446     }
447     return status_success;
448 }
449 
clock_set_source_divider(clock_name_t clock_name,clk_src_t src,uint32_t div)450 hpm_stat_t clock_set_source_divider(clock_name_t clock_name, clk_src_t src, uint32_t div)
451 {
452     hpm_stat_t status = status_success;
453     uint32_t clk_src_type = GET_CLK_SRC_GROUP_FROM_NAME(clock_name);
454     uint32_t node_or_instance = GET_CLK_NODE_FROM_NAME(clock_name);
455     switch (clk_src_type) {
456     case CLK_SRC_GROUP_COMMON:
457         if ((div < 1U) || (div > 256U)) {
458             status = status_clk_div_invalid;
459         } else {
460             clock_source_t clk_src = GET_CLOCK_SOURCE_FROM_CLK_SRC(src);
461             sysctl_config_clock(HPM_SYSCTL, (clock_node_t) node_or_instance, clk_src, div);
462         }
463         break;
464     case CLK_SRC_GROUP_ADC:
465     case CLK_SRC_GROUP_DAC:
466     case CLK_SRC_GROUP_WDG:
467     case CLK_SRC_GROUP_PWDG:
468     case CLK_SRC_GROUP_SRC:
469         status = status_clk_operation_unsupported;
470         break;
471     case CLK_SRC_GROUP_PMIC:
472         status = status_clk_fixed;
473         break;
474     case CLK_SRC_GROUP_AHB:
475         status = status_clk_shared_cpu0;
476         break;
477     case CLK_SRC_GROUP_AXI:
478         status = status_clk_shared_cpu0;
479         break;
480     case CLK_SRC_GROUP_CPU0:
481         if (node_or_instance == clock_node_cpu0) {
482             /* Note: the AXI and AHB BUS share the same CPU clock, once the CPU clock frequency
483              *  changes, the AXI and AHB clock changes accordingly, here the driver ensures the
484              *  AXI and AHB bus clock frequency is in valid range.
485              */
486             uint32_t expected_freq = get_frequency_for_source((clock_source_t) src) / div;
487             uint32_t axi_sub_div = (expected_freq + BUS_FREQ_MAX - 1U) / BUS_FREQ_MAX;
488             uint32_t ahb_sub_div = (expected_freq + BUS_FREQ_MAX - 1U) / BUS_FREQ_MAX;
489             sysctl_config_cpu0_domain_clock(HPM_SYSCTL, (clock_source_t) src, div, axi_sub_div, ahb_sub_div);
490         } else {
491             status = status_clk_shared_cpu0;
492         }
493         break;
494     default:
495         status = status_clk_src_invalid;
496         break;
497     }
498 
499     return status;
500 }
501 
switch_ip_clock(clock_name_t clock_name,bool on)502 static void switch_ip_clock(clock_name_t clock_name, bool on)
503 {
504     uint32_t resource = GET_CLK_RESOURCE_FROM_NAME(clock_name);
505 
506     if (resource < sysctl_resource_end) {
507         uint32_t mode = on ? 1UL : 2UL;
508         HPM_SYSCTL->RESOURCE[resource] =
509             (HPM_SYSCTL->RESOURCE[resource] & ~SYSCTL_RESOURCE_MODE_MASK) | SYSCTL_RESOURCE_MODE_SET(mode);
510     }
511 }
512 
clock_enable(clock_name_t clock_name)513 void clock_enable(clock_name_t clock_name)
514 {
515     switch_ip_clock(clock_name, CLOCK_ON);
516 }
517 
clock_disable(clock_name_t clock_name)518 void clock_disable(clock_name_t clock_name)
519 {
520     switch_ip_clock(clock_name, CLOCK_OFF);
521 }
522 
clock_add_to_group(clock_name_t clock_name,uint32_t group)523 void clock_add_to_group(clock_name_t clock_name, uint32_t group)
524 {
525     uint32_t resource = GET_CLK_RESOURCE_FROM_NAME(clock_name);
526 
527     if (resource < sysctl_resource_end) {
528         sysctl_enable_group_resource(HPM_SYSCTL, group, resource, true);
529     }
530 }
531 
clock_remove_from_group(clock_name_t clock_name,uint32_t group)532 void clock_remove_from_group(clock_name_t clock_name, uint32_t group)
533 {
534     uint32_t resource = GET_CLK_RESOURCE_FROM_NAME(clock_name);
535 
536     if (resource < sysctl_resource_end) {
537         sysctl_enable_group_resource(HPM_SYSCTL, group, resource, false);
538     }
539 }
540 
clock_check_in_group(clock_name_t clock_name,uint32_t group)541 bool clock_check_in_group(clock_name_t clock_name, uint32_t group)
542 {
543     uint32_t resource = GET_CLK_RESOURCE_FROM_NAME(clock_name);
544 
545     return sysctl_check_group_resource_enable(HPM_SYSCTL, group, resource);
546 }
547 
clock_connect_group_to_cpu(uint32_t group,uint32_t cpu)548 void clock_connect_group_to_cpu(uint32_t group, uint32_t cpu)
549 {
550     if (cpu < 2U) {
551         HPM_SYSCTL->AFFILIATE[cpu].SET = (1UL << group);
552     }
553 }
554 
clock_disconnect_group_from_cpu(uint32_t group,uint32_t cpu)555 void clock_disconnect_group_from_cpu(uint32_t group, uint32_t cpu)
556 {
557     if (cpu < 2U) {
558         HPM_SYSCTL->AFFILIATE[cpu].CLEAR = (1UL << group);
559     }
560 }
561 
clock_cpu_delay_us(uint32_t us)562 void clock_cpu_delay_us(uint32_t us)
563 {
564     uint32_t ticks_per_us = (hpm_core_clock + FREQ_1MHz - 1U) / FREQ_1MHz;
565     uint64_t expected_ticks = hpm_csr_get_core_cycle() + ticks_per_us * us;
566     while (hpm_csr_get_core_cycle() < expected_ticks) {
567     }
568 }
569 
clock_cpu_delay_ms(uint32_t ms)570 void clock_cpu_delay_ms(uint32_t ms)
571 {
572     uint32_t ticks_per_us = (hpm_core_clock + FREQ_1MHz - 1U) / FREQ_1MHz;
573     uint64_t expected_ticks = hpm_csr_get_core_cycle() + (uint64_t) ticks_per_us * 1000UL * ms;
574     while (hpm_csr_get_core_cycle() < expected_ticks) {
575     }
576 }
577 
clock_update_core_clock(void)578 void clock_update_core_clock(void)
579 {
580     uint32_t hart_id = read_csr(CSR_MHARTID);
581     clock_name_t cpu_clk_name = (hart_id == 1U) ? clock_cpu1 : clock_cpu0;
582     hpm_core_clock = clock_get_frequency(cpu_clk_name);
583 }
584