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