• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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