• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 HPMicro
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 #include "hpm_common.h"
8 #include "hpm_soc.h"
9 #include "hpm_clock_drv.h"
10 #include "hpm_sysctl_drv.h"
11 #include "hpm_pllctl_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 (648000000UL)
22 #define FREQ_PRESET1_PLL1_CLK0 (266000000UL)
23 #define FREQ_PRESET1_PLL1_CLK1 (400000000UL)
24 #define FREQ_PRESET1_PLL2_CLK0 (333000000UL)
25 #define FREQ_PRESET1_PLL2_CLK1 (250000000UL)
26 #define FREQ_PRESET1_PLL3_CLK0 (614400000UL)
27 #define FREQ_PRESET1_PLL4_CLK0 (594000000UL)
28 #define FREQ_32KHz (32768UL)
29 #define ADC_INSTANCE_NUM ARRAY_SIZE(HPM_SYSCTL->ADCCLK)
30 #define I2S_INSTANCE_NUM ARRAY_SIZE(HPM_SYSCTL->I2SCLK)
31 #define WDG_INSTANCE_NUM (4U)
32 
33 /* Clock On/Off definitions */
34 #define CLOCK_ON (true)
35 #define CLOCK_OFF (false)
36 
37 
38 /***********************************************************************************************************************
39  * Prototypes
40  **********************************************************************************************************************/
41 
42 /**
43  * @brief Get Clock frequency for selected clock source
44  */
45 static uint32_t get_frequency_for_source(clock_source_t source);
46 
47 /**
48  * @brief Get Clock frequency for IP in common group
49  */
50 static uint32_t get_frequency_for_ip_in_common_group(clock_node_t node);
51 
52 /**
53  * @brief Get Clock frequency for I2S or ADC
54  */
55 static uint32_t get_frequency_for_i2s_or_adc(uint32_t clk_src_type, uint32_t instance);
56 
57 /**
58  * @brief Get Clock frequency for WDG
59  */
60 static uint32_t get_frequency_for_wdg(uint32_t instance);
61 
62 /**
63  * @brief Turn on/off the IP clock
64  */
65 static void switch_ip_clock(clock_name_t clock_name, bool on);
66 
67 static uint64_t get_core_mcycle(void);
68 
69 /***********************************************************************************************************************
70  * Variables
71  **********************************************************************************************************************/
72 static const clock_node_t s_adc_clk_mux_node[] = {
73         clock_node_ahb0,
74         clock_node_ana0,
75         clock_node_ana1,
76         clock_node_ana2,
77 };
78 static const clock_node_t s_i2s_clk_mux_node[] = {
79         clock_node_ahb0,
80         clock_node_aud0,
81         clock_node_aud1,
82         clock_node_aud2,
83 };
84 
85 static WDG_Type *const s_wdgs[] = { HPM_WDG0, HPM_WDG1, HPM_WDG2, HPM_WDG3 };
86 
87 uint32_t hpm_core_clock;
88 
89 /***********************************************************************************************************************
90  * Codes
91  **********************************************************************************************************************/
clock_get_frequency(clock_name_t clock_name)92 uint32_t clock_get_frequency(clock_name_t clock_name)
93 {
94     uint32_t clk_freq = 0UL;
95     uint32_t clk_src_type = GET_CLK_SRC_GROUP_FROM_NAME(clock_name);
96     uint32_t node_or_instance = GET_CLK_NODE_FROM_NAME(clock_name);
97     switch (clk_src_type) {
98     case CLK_SRC_GROUP_COMMON:
99         clk_freq = get_frequency_for_ip_in_common_group((clock_node_t) node_or_instance);
100         break;
101     case CLK_SRC_GROUP_ADC:
102         clk_freq = get_frequency_for_i2s_or_adc(CLK_SRC_GROUP_ADC, node_or_instance);
103         break;
104     case CLK_SRC_GROUP_I2S:
105         clk_freq = get_frequency_for_i2s_or_adc(CLK_SRC_GROUP_I2S, node_or_instance);
106         break;
107     case CLK_SRC_GROUP_WDG:
108         clk_freq = get_frequency_for_wdg(node_or_instance);
109         break;
110     case CLK_SRC_GROUP_PMIC:
111         clk_freq = FREQ_PRESET1_OSC0_CLK0;
112         break;
113     case CLK_SRC_GROUP_AHB:
114         clk_freq = get_frequency_for_ip_in_common_group(clock_node_ahb0);
115         break;
116     case CLK_SRC_GROUP_AXI0:
117         clk_freq = get_frequency_for_ip_in_common_group(clock_node_axi0);
118         break;
119     case CLK_SRC_GROUP_AXI1:
120         clk_freq = get_frequency_for_ip_in_common_group(clock_node_axi1);
121         break;
122     case CLK_SRC_GROUP_AXI2:
123         clk_freq = get_frequency_for_ip_in_common_group(clock_node_axi2);
124         break;
125     case CLK_SRC_GROUP_CPU0:
126         clk_freq = get_frequency_for_ip_in_common_group(clock_node_cpu0);
127         break;
128     case CLK_SRC_GROUP_CPU1:
129         clk_freq = get_frequency_for_ip_in_common_group(clock_node_cpu1);
130         break;
131     case CLK_SRC_GROUP_SRC:
132         clk_freq = get_frequency_for_source((clock_source_t) node_or_instance);
133         break;
134     default:
135         clk_freq = 0UL;
136         break;
137     }
138     return clk_freq;
139 }
140 
get_frequency_for_source(clock_source_t source)141 static uint32_t get_frequency_for_source(clock_source_t source)
142 {
143     uint32_t clk_freq = 0UL;
144     uint32_t div = 1;
145     switch (source) {
146     case clock_source_osc0_clk0:
147         clk_freq = FREQ_PRESET1_OSC0_CLK0;
148         break;
149     case clock_source_pll0_clk0:
150         clk_freq = pllctl_get_pll_freq_in_hz(HPM_PLLCTL, 0U);
151         break;
152     case clock_source_pll1_clk0:
153         div = pllctl_get_div(HPM_PLLCTL, 1, 0);
154         clk_freq = pllctl_get_pll_freq_in_hz(HPM_PLLCTL, 1U) / div;
155         break;
156     case clock_source_pll1_clk1:
157         div = pllctl_get_div(HPM_PLLCTL, 1, 1);
158         clk_freq = pllctl_get_pll_freq_in_hz(HPM_PLLCTL, 1U) / div;
159         break;
160     case clock_source_pll2_clk0:
161         div = pllctl_get_div(HPM_PLLCTL, 2, 0);
162         clk_freq = pllctl_get_pll_freq_in_hz(HPM_PLLCTL, 2U) / div;
163         break;
164     case clock_source_pll2_clk1:
165         div = pllctl_get_div(HPM_PLLCTL, 2, 1);
166         clk_freq = pllctl_get_pll_freq_in_hz(HPM_PLLCTL, 2U) / div;
167         break;
168     case clock_source_pll3_clk0:
169         clk_freq = pllctl_get_pll_freq_in_hz(HPM_PLLCTL, 3U);
170         break;
171     case clock_source_pll4_clk0:
172         clk_freq = pllctl_get_pll_freq_in_hz(HPM_PLLCTL, 4U);
173         break;
174     default:
175         clk_freq = 0UL;
176         break;
177     }
178 
179     return clk_freq;
180 }
181 
get_frequency_for_ip_in_common_group(clock_node_t node)182 static uint32_t get_frequency_for_ip_in_common_group(clock_node_t node)
183 {
184     uint32_t clk_freq = 0UL;
185     uint32_t node_or_instance = GET_CLK_NODE_FROM_NAME(node);
186 
187     if (node_or_instance < clock_node_end) {
188         uint32_t clk_node = (uint32_t) node_or_instance;
189 
190         uint32_t clk_div = 1UL + SYSCTL_CLOCK_DIV_GET(HPM_SYSCTL->CLOCK[clk_node]);
191         clock_source_t clk_mux = (clock_source_t) SYSCTL_CLOCK_MUX_GET(HPM_SYSCTL->CLOCK[clk_node]);
192         clk_freq = get_frequency_for_source(clk_mux) / clk_div;
193     }
194     return clk_freq;
195 }
196 
get_frequency_for_i2s_or_adc(uint32_t clk_src_type,uint32_t instance)197 static uint32_t get_frequency_for_i2s_or_adc(uint32_t clk_src_type, uint32_t instance)
198 {
199     uint32_t clk_freq = 0UL;
200     bool is_mux_valid = false;
201     clock_node_t node = clock_node_end;
202     if (clk_src_type == CLK_SRC_GROUP_ADC) {
203         uint32_t adc_index = instance;
204         if (adc_index < ADC_INSTANCE_NUM) {
205             uint32_t mux_in_reg = SYSCTL_ADCCLK_MUX_GET(HPM_SYSCTL->ADCCLK[adc_index]);
206             if (mux_in_reg < ARRAY_SIZE(s_adc_clk_mux_node)) {
207                 node = s_adc_clk_mux_node[mux_in_reg];
208                 is_mux_valid = true;
209             }
210         }
211     } else {
212         uint32_t i2s_index = instance;
213         if (i2s_index < I2S_INSTANCE_NUM) {
214             uint32_t mux_in_reg = SYSCTL_I2SCLK_MUX_GET(HPM_SYSCTL->I2SCLK[i2s_index]);
215             if (mux_in_reg < ARRAY_SIZE(s_i2s_clk_mux_node)) {
216                 node = s_i2s_clk_mux_node[mux_in_reg];
217                 is_mux_valid = true;
218             }
219         }
220     }
221 
222     if (is_mux_valid) {
223         clk_freq = get_frequency_for_ip_in_common_group(node);
224     }
225     return clk_freq;
226 }
227 
get_frequency_for_wdg(uint32_t instance)228 static uint32_t get_frequency_for_wdg(uint32_t instance)
229 {
230     uint32_t freq_in_hz;
231     /* EXT clock is chosen */
232     if (WDG_CTRL_CLKSEL_GET(s_wdgs[instance]->CTRL) == 0) {
233         freq_in_hz = get_frequency_for_ip_in_common_group(clock_node_ahb0);
234     }
235         /* PCLK is chosen */
236     else {
237         freq_in_hz = FREQ_32KHz;
238     }
239 
240     return freq_in_hz;
241 }
242 
clock_get_source(clock_name_t clock_name)243 clk_src_t clock_get_source(clock_name_t clock_name)
244 {
245     uint8_t clk_src_group = CLK_SRC_GROUP_INVALID;
246     uint8_t clk_src_index = 0xFU;
247     uint32_t clk_src_type = GET_CLK_SRC_GROUP_FROM_NAME(clock_name);
248     uint32_t node_or_instance = GET_CLK_NODE_FROM_NAME(clock_name);
249     switch (clk_src_type) {
250     case CLK_SRC_GROUP_COMMON:
251         clk_src_group = CLK_SRC_GROUP_COMMON;
252         clk_src_index = SYSCTL_CLOCK_MUX_GET(HPM_SYSCTL->CLOCK[node_or_instance]);
253         break;
254     case CLK_SRC_GROUP_ADC:
255         if (node_or_instance < ADC_INSTANCE_NUM) {
256             clk_src_group = CLK_SRC_GROUP_ADC;
257             clk_src_index = SYSCTL_ADCCLK_MUX_GET(HPM_SYSCTL->ADCCLK[node_or_instance]);
258         }
259         break;
260     case CLK_SRC_GROUP_I2S:
261         if (node_or_instance < I2S_INSTANCE_NUM) {
262             clk_src_group = CLK_SRC_GROUP_I2S;
263             clk_src_index = SYSCTL_I2SCLK_MUX_GET(HPM_SYSCTL->I2SCLK[node_or_instance]);
264         }
265         break;
266     case CLK_SRC_GROUP_WDG:
267         if (node_or_instance < WDG_INSTANCE_NUM) {
268             clk_src_group = CLK_SRC_GROUP_WDG;
269             clk_src_index = (WDG_CTRL_CLKSEL_GET(s_wdgs[node_or_instance]->CTRL) == 0);
270         }
271         break;
272     case CLK_SRC_GROUP_PMIC:
273         clk_src_group = CLK_SRC_GROUP_COMMON;
274         clk_src_index = clock_source_osc0_clk0;
275         break;
276     case CLK_SRC_GROUP_AHB:
277         clk_src_group = CLK_SRC_GROUP_COMMON;
278         clk_src_index = SYSCTL_CLOCK_MUX_GET(HPM_SYSCTL->CLOCK[(uint32_t) clock_node_ahb0]);
279         break;
280     case CLK_SRC_GROUP_AXI0:
281         clk_src_group = CLK_SRC_GROUP_COMMON;
282         clk_src_index = SYSCTL_CLOCK_MUX_GET(HPM_SYSCTL->CLOCK[(uint32_t) clock_node_axi0]);
283         break;
284     case CLK_SRC_GROUP_AXI1:
285         clk_src_group = CLK_SRC_GROUP_COMMON;
286         clk_src_index = SYSCTL_CLOCK_MUX_GET(HPM_SYSCTL->CLOCK[(uint32_t) clock_node_axi1]);
287         break;
288     case CLK_SRC_GROUP_AXI2:
289         clk_src_group = CLK_SRC_GROUP_COMMON;
290         clk_src_index = SYSCTL_CLOCK_MUX_GET(HPM_SYSCTL->CLOCK[(uint32_t) clock_node_axi2]);
291         break;
292     case CLK_SRC_GROUP_CPU0:
293         clk_src_group = CLK_SRC_GROUP_COMMON;
294         clk_src_index = SYSCTL_CLOCK_MUX_GET(HPM_SYSCTL->CLOCK[(uint32_t) clock_node_cpu0]);
295         break;
296     case CLK_SRC_GROUP_CPU1:
297         clk_src_group = CLK_SRC_GROUP_COMMON;
298         clk_src_index = SYSCTL_CLOCK_MUX_GET(HPM_SYSCTL->CLOCK[(uint32_t) clock_node_cpu1]);
299         break;
300     case CLK_SRC_GROUP_SRC:
301         clk_src_index = (clk_src_t) node_or_instance;
302         break;
303     default:
304         clk_src_group = CLK_SRC_GROUP_INVALID;
305         break;
306     }
307 
308     clk_src_t clk_src;
309     if (clk_src_group != CLK_SRC_GROUP_INVALID) {
310         clk_src = MAKE_CLK_SRC(clk_src_group, clk_src_index);
311     } else {
312         clk_src = clk_src_invalid;
313     }
314 
315     return clk_src;
316 }
317 
clock_set_adc_source(clock_name_t clock_name,clk_src_t src)318 hpm_stat_t clock_set_adc_source(clock_name_t clock_name, clk_src_t src)
319 {
320     uint32_t clk_src_type = GET_CLK_SRC_GROUP_FROM_NAME(clock_name);
321     uint32_t node_or_instance = GET_CLK_NODE_FROM_NAME(clock_name);
322 
323     if ((clk_src_type != CLK_SRC_GROUP_ADC) || (node_or_instance >= ADC_INSTANCE_NUM)) {
324         return status_clk_invalid;
325     }
326 
327     if ((src <= clk_adc_src_ahb0) || (src >= clk_adc_src_ana2)) {
328         return status_clk_src_invalid;
329     }
330 
331     uint32_t clk_src_index = GET_CLK_SRC_INDEX(src);
332     HPM_SYSCTL->ADCCLK[node_or_instance] =
333             (HPM_SYSCTL->ADCCLK[node_or_instance] & SYSCTL_ADCCLK_MUX_MASK) | SYSCTL_ADCCLK_MUX_SET(clk_src_index);
334 
335     return status_success;
336 }
337 
clock_set_i2s_source(clock_name_t clock_name,clk_src_t src)338 hpm_stat_t clock_set_i2s_source(clock_name_t clock_name, clk_src_t src)
339 {
340     uint32_t clk_src_type = GET_CLK_SRC_GROUP_FROM_NAME(clock_name);
341     uint32_t node_or_instance = GET_CLK_NODE_FROM_NAME(clock_name);
342 
343     if ((clk_src_type != CLK_SRC_GROUP_I2S) || (node_or_instance >= I2S_INSTANCE_NUM)) {
344         return status_clk_invalid;
345     }
346 
347     if ((src <= clk_i2s_src_ahb0) || (src >= clk_i2s_src_aud2)) {
348         return status_clk_src_invalid;
349     }
350 
351     uint32_t clk_src_index = GET_CLK_SRC_INDEX(src);
352     HPM_SYSCTL->I2SCLK[node_or_instance] =
353             (HPM_SYSCTL->I2SCLK[node_or_instance] & SYSCTL_I2SCLK_MUX_MASK) | SYSCTL_I2SCLK_MUX_SET(clk_src_index);
354 
355     return status_success;
356 }
357 
clock_set_source_divider(clock_name_t clock_name,clk_src_t src,uint32_t div)358 hpm_stat_t clock_set_source_divider(clock_name_t clock_name, clk_src_t src, uint32_t div)
359 {
360     hpm_stat_t status = status_success;
361     uint32_t clk_src_type = GET_CLK_SRC_GROUP_FROM_NAME(clock_name);
362     uint32_t node_or_instance = GET_CLK_NODE_FROM_NAME(clock_name);
363     switch (clk_src_type) {
364     case CLK_SRC_GROUP_COMMON:
365         if ((div < 1U) || (div > 256U)) {
366             status = status_clk_div_invalid;
367         } else {
368             clock_source_t clk_src = GET_CLOCK_SOURCE_FROM_CLK_SRC(src);
369             sysctl_config_clock(HPM_SYSCTL, (clock_node_t) node_or_instance, clk_src, div);
370         }
371         break;
372     case CLK_SRC_GROUP_ADC:
373         status = status_clk_operation_unsupported;
374         break;
375     case CLK_SRC_GROUP_I2S:
376         status = status_clk_operation_unsupported;
377         break;
378     case CLK_SRC_GROUP_WDG:
379         if (node_or_instance < WDG_INSTANCE_NUM) {
380             if (src == clk_wdg_src_ahb0) {
381                 s_wdgs[node_or_instance]->CTRL &= ~WDG_CTRL_CLKSEL_MASK;
382             } else if (src == clk_wdg_src_osc32k) {
383                 s_wdgs[node_or_instance]->CTRL |= WDG_CTRL_CLKSEL_MASK;
384             } else {
385                 status = status_clk_src_invalid;
386             }
387         }
388         break;
389     case CLK_SRC_GROUP_PMIC:
390         status = status_clk_fixed;
391         break;
392     case CLK_SRC_GROUP_AHB:
393         status = status_clk_shared_ahb;
394         break;
395     case CLK_SRC_GROUP_AXI0:
396         status = status_clk_shared_axi0;
397         break;
398     case CLK_SRC_GROUP_AXI1:
399         status = status_clk_shared_axi1;
400         break;
401     case CLK_SRC_GROUP_AXI2:
402         status = status_clk_shared_axi2;
403         break;
404     case CLK_SRC_GROUP_CPU0:
405         status = status_clk_shared_cpu0;
406         break;
407     case CLK_SRC_GROUP_CPU1:
408         status = status_clk_shared_cpu1;
409         break;
410     case CLK_SRC_GROUP_SRC:
411         status = status_clk_operation_unsupported;
412         break;
413     default:
414         status = status_clk_src_invalid;
415         break;
416     }
417 
418     return status;
419 }
420 
switch_ip_clock(clock_name_t clock_name,bool on)421 void switch_ip_clock(clock_name_t clock_name, bool on)
422 {
423     uint32_t resource = GET_CLK_RESOURCE_FROM_NAME(clock_name);
424 
425     if (resource < sysctl_resource_end) {
426         uint32_t mode = on ? 1UL : 2UL;
427         HPM_SYSCTL->RESOURCE[resource] =
428                 (HPM_SYSCTL->RESOURCE[resource] & ~SYSCTL_RESOURCE_MODE_MASK) | SYSCTL_RESOURCE_MODE_SET(mode);
429     }
430 }
431 
432 
clock_enable(clock_name_t clock_name)433 void clock_enable(clock_name_t clock_name)
434 {
435     switch_ip_clock(clock_name, CLOCK_ON);
436 }
437 
clock_disable(clock_name_t clock_name)438 void clock_disable(clock_name_t clock_name)
439 {
440     switch_ip_clock(clock_name, CLOCK_OFF);
441 }
442 
clock_add_to_group(clock_name_t clock_name,uint32_t group)443 void clock_add_to_group(clock_name_t clock_name, uint32_t group)
444 {
445     uint32_t resource = GET_CLK_RESOURCE_FROM_NAME(clock_name);
446 
447     if (resource < sysctl_resource_end) {
448         sysctl_enable_group_resource(HPM_SYSCTL, group, resource, true);
449     }
450 }
451 
clock_remove_from_group(clock_name_t clock_name,uint32_t group)452 void clock_remove_from_group(clock_name_t clock_name, uint32_t group)
453 {
454     uint32_t resource = GET_CLK_RESOURCE_FROM_NAME(clock_name);
455 
456     if (resource < sysctl_resource_end) {
457         sysctl_enable_group_resource(HPM_SYSCTL, group, resource, false);
458     }
459 }
460 
clock_connect_group_to_cpu(uint32_t group,uint32_t cpu)461 void clock_connect_group_to_cpu(uint32_t group, uint32_t cpu)
462 {
463     if (cpu < 2U) {
464         HPM_SYSCTL->AFFILIATE[cpu].SET = (1UL << group);
465     }
466 }
467 
clock_disconnect_group_from_cpu(uint32_t group,uint32_t cpu)468 void clock_disconnect_group_from_cpu(uint32_t group, uint32_t cpu)
469 {
470     if (cpu < 2U) {
471         HPM_SYSCTL->AFFILIATE[cpu].CLEAR = (1UL << group);
472     }
473 }
474 
475 
get_core_mcycle(void)476 static uint64_t get_core_mcycle(void)
477 {
478     uint64_t result;
479     uint32_t resultl_first = read_csr(CSR_CYCLE);
480     uint32_t resulth = read_csr(CSR_CYCLEH);
481     uint32_t resultl_second = read_csr(CSR_CYCLE);
482     if (resultl_first < resultl_second) {
483         result = ((uint64_t)resulth << 32) | resultl_first; /* if MCYCLE didn't roll over, return the value directly */
484     } else {
485         resulth = read_csr(CSR_CYCLEH);
486         result = ((uint64_t)resulth << 32) | resultl_second; /* if MCYCLE rolled over, need to get the MCYCLEH again */
487     }
488     return result;
489  }
490 
clock_cpu_delay_us(uint32_t us)491 void clock_cpu_delay_us(uint32_t us)
492 {
493     uint32_t ticks_per_us = (hpm_core_clock + FREQ_1MHz - 1U) / FREQ_1MHz;
494     uint64_t expected_ticks = get_core_mcycle() + ticks_per_us * us;
495     while (get_core_mcycle() < expected_ticks) {
496     }
497 }
498 
clock_cpu_delay_ms(uint32_t ms)499 void clock_cpu_delay_ms(uint32_t ms)
500 {
501     uint32_t ticks_per_us = (hpm_core_clock + FREQ_1MHz - 1U) / FREQ_1MHz;
502     uint64_t expected_ticks = get_core_mcycle() + (uint64_t)ticks_per_us * 1000UL * ms;
503     while (get_core_mcycle() < expected_ticks) {
504     }
505 }
506 
clock_update_core_clock(void)507 void clock_update_core_clock(void)
508 {
509     uint32_t hart_id = read_csr(CSR_MHARTID);
510     clock_name_t cpu_clk_name = (hart_id == 1U) ? clock_cpu1 : clock_cpu0;
511     hpm_core_clock = clock_get_frequency(cpu_clk_name);
512 }