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 }