1 /*
2  * Copyright (c) 2021-2024 HPMicro
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 #ifndef HPM_CLOCK_DRV_H
8 #define HPM_CLOCK_DRV_H
9 
10 #include "hpm_common.h"
11 #include "hpm_sysctl_drv.h"
12 #include "hpm_csr_drv.h"
13 
14 
15 #define CLOCK_DIV_INVALID (~0UL)
16 
17 /**
18  * @brief Error codes for clock driver
19  */
20 enum {
21     status_clk_div_invalid = MAKE_STATUS(status_group_clk, 0),
22     status_clk_src_invalid = MAKE_STATUS(status_group_clk, 1),
23     status_clk_invalid = MAKE_STATUS(status_group_clk, 2),
24     status_clk_operation_unsupported = MAKE_STATUS(status_group_clk, 3),
25     status_clk_shared_ahb = MAKE_STATUS(status_group_clk, 4),
26     status_clk_shared_axi0 = MAKE_STATUS(status_group_clk, 5),
27     status_clk_shared_axi1 = MAKE_STATUS(status_group_clk, 6),
28     status_clk_shared_axi2 = MAKE_STATUS(status_group_clk, 7),
29     status_clk_shared_cpu0 = MAKE_STATUS(status_group_clk, 8),
30     status_clk_shared_cpu1 = MAKE_STATUS(status_group_clk, 9),
31     status_clk_fixed = MAKE_STATUS(status_group_clk, 10),
32 };
33 
34 /**
35  * @brief Clock source group definitions
36  */
37 #define CLK_SRC_GROUP_COMMON (0U)
38 #define CLK_SRC_GROUP_ADC    (1U)
39 #define CLK_SRC_GROUP_EWDG   (3U)
40 #define CLK_SRC_GROUP_PMIC   (4U)
41 #define CLK_SRC_GROUP_AHB    (5U)
42 #define CLK_SRC_GROUP_DAC   (7U)
43 #define CLK_SRC_GROUP_CPU0   (9U)
44 #define CLK_SRC_GROUP_SRC    (10U)
45 #define CLK_SRC_GROUP_PEWDG    (11U)
46 #define CLK_SRC_GROUP_INVALID (15U)
47 
48 #define MAKE_CLK_SRC(src_grp, index) (((uint8_t)(src_grp)<<4) | (index))
49 #define GET_CLK_SRC_GROUP(src) (((uint8_t)(src)>>4) & 0x0FU)
50 #define GET_CLK_SRC_INDEX(src) ((uint8_t)(src) & 0x0FU)
51 
52 #define GET_CLOCK_SOURCE_FROM_CLK_SRC(clk_src) (clock_source_t)((uint32_t)(clk_src) & 0xFU)
53 
54 /**
55  * @brief Clock source definitions
56  */
57 typedef enum _clock_sources {
58     clk_src_osc24m = MAKE_CLK_SRC(CLK_SRC_GROUP_COMMON, 0),
59     clk_src_pll0_clk0 = MAKE_CLK_SRC(CLK_SRC_GROUP_COMMON, 1),
60     clk_src_pll0_clk1 = MAKE_CLK_SRC(CLK_SRC_GROUP_COMMON, 2),
61     clk_src_pll0_clk2 = MAKE_CLK_SRC(CLK_SRC_GROUP_COMMON, 3),
62     clk_src_pll1_clk0 = MAKE_CLK_SRC(CLK_SRC_GROUP_COMMON, 4),
63     clk_src_pll1_clk1 = MAKE_CLK_SRC(CLK_SRC_GROUP_COMMON, 5),
64     clk_src_pll1_clk2 = MAKE_CLK_SRC(CLK_SRC_GROUP_COMMON, 6),
65     clk_src_pll1_clk3 = MAKE_CLK_SRC(CLK_SRC_GROUP_COMMON, 7),
66     clk_src_osc32k = MAKE_CLK_SRC(CLK_SRC_GROUP_COMMON, 8),
67 
68     clk_adc_src_ahb0 = MAKE_CLK_SRC(CLK_SRC_GROUP_ADC, 0),
69     clk_adc_src_ana0 = MAKE_CLK_SRC(CLK_SRC_GROUP_ADC, 1),
70     clk_adc_src_ana1 = MAKE_CLK_SRC(CLK_SRC_GROUP_ADC, 1),
71 
72     clk_dac_src_ahb0 = MAKE_CLK_SRC(CLK_SRC_GROUP_DAC, 0),
73     clk_dac_src_ana2 = MAKE_CLK_SRC(CLK_SRC_GROUP_DAC, 1),
74     clk_dac_src_ana3 = MAKE_CLK_SRC(CLK_SRC_GROUP_DAC, 1),
75 
76     clk_wdg_src_ahb0 = MAKE_CLK_SRC(CLK_SRC_GROUP_EWDG, 0),
77     clk_wdg_src_osc32k = MAKE_CLK_SRC(CLK_SRC_GROUP_EWDG, 1),
78 
79     clk_pwdg_src_osc24m = MAKE_CLK_SRC(CLK_SRC_GROUP_PEWDG, 0),
80     clk_pwdg_src_osc32k = MAKE_CLK_SRC(CLK_SRC_GROUP_PEWDG, 1),
81 
82     clk_src_invalid = MAKE_CLK_SRC(CLK_SRC_GROUP_INVALID, 15),
83 } clk_src_t;
84 
85 
86 #define RESOURCE_INVALID (0xFFFFU)
87 #define RESOURCE_SHARED_CPU0 (0xFFFDU)
88 
89 /* Clock NAME related Macros */
90 #define MAKE_CLOCK_NAME(resource, src_type, node) (((uint32_t)(resource) << 16) | ((uint32_t)(src_type) << 8) | ((uint32_t)(node)))
91 #define GET_CLK_SRC_GROUP_FROM_NAME(name)  (((uint32_t)(name) >> 8) & 0xFFUL)
92 #define GET_CLK_NODE_FROM_NAME(name) ((uint32_t)(name) & 0xFFUL)
93 #define GET_CLK_RESOURCE_FROM_NAME(name) ((uint32_t)(name) >> 16)
94 
95 /**
96  * @brief Peripheral Clock Type Description
97  */
98 typedef enum _clock_name {
99     clock_cpu0 = MAKE_CLOCK_NAME(sysctl_resource_cpu0, CLK_SRC_GROUP_CPU0, clock_node_cpu0),
100 
101     clock_mchtmr0 = MAKE_CLOCK_NAME(sysctl_resource_mchtmr0, CLK_SRC_GROUP_COMMON, clock_node_mchtmr0),
102     clock_can0 = MAKE_CLOCK_NAME(sysctl_resource_can0, CLK_SRC_GROUP_COMMON, clock_node_can0),
103     clock_can1 = MAKE_CLOCK_NAME(sysctl_resource_can1, CLK_SRC_GROUP_COMMON, clock_node_can1),
104     clock_can2 = MAKE_CLOCK_NAME(sysctl_resource_can2, CLK_SRC_GROUP_COMMON, clock_node_can2),
105     clock_can3 = MAKE_CLOCK_NAME(sysctl_resource_can3, CLK_SRC_GROUP_COMMON, clock_node_can3),
106     clock_gptmr0 = MAKE_CLOCK_NAME(sysctl_resource_gptmr0, CLK_SRC_GROUP_COMMON, clock_node_gptmr0),
107     clock_gptmr1 = MAKE_CLOCK_NAME(sysctl_resource_gptmr1, CLK_SRC_GROUP_COMMON, clock_node_gptmr1),
108     clock_gptmr2 = MAKE_CLOCK_NAME(sysctl_resource_gptmr2, CLK_SRC_GROUP_COMMON, clock_node_gptmr2),
109     clock_gptmr3 = MAKE_CLOCK_NAME(sysctl_resource_gptmr3, CLK_SRC_GROUP_COMMON, clock_node_gptmr3),
110     clock_i2c0 = MAKE_CLOCK_NAME(sysctl_resource_i2c0, CLK_SRC_GROUP_COMMON, clock_node_i2c0),
111     clock_i2c1 = MAKE_CLOCK_NAME(sysctl_resource_i2c1, CLK_SRC_GROUP_COMMON, clock_node_i2c1),
112     clock_i2c2 = MAKE_CLOCK_NAME(sysctl_resource_i2c2, CLK_SRC_GROUP_COMMON, clock_node_i2c2),
113     clock_i2c3 = MAKE_CLOCK_NAME(sysctl_resource_i2c3, CLK_SRC_GROUP_COMMON, clock_node_i2c3),
114     clock_spi0 = MAKE_CLOCK_NAME(sysctl_resource_spi0, CLK_SRC_GROUP_COMMON, clock_node_spi0),
115     clock_spi1 = MAKE_CLOCK_NAME(sysctl_resource_spi1, CLK_SRC_GROUP_COMMON, clock_node_spi1),
116     clock_spi2 = MAKE_CLOCK_NAME(sysctl_resource_spi2, CLK_SRC_GROUP_COMMON, clock_node_spi2),
117     clock_spi3 = MAKE_CLOCK_NAME(sysctl_resource_spi3, CLK_SRC_GROUP_COMMON, clock_node_spi3),
118     clock_uart0 = MAKE_CLOCK_NAME(sysctl_resource_uart0, CLK_SRC_GROUP_COMMON, clock_node_uart0),
119     clock_uart1 = MAKE_CLOCK_NAME(sysctl_resource_uart1, CLK_SRC_GROUP_COMMON, clock_node_uart1),
120     clock_uart2 = MAKE_CLOCK_NAME(sysctl_resource_uart2, CLK_SRC_GROUP_COMMON, clock_node_uart2),
121     clock_uart3 = MAKE_CLOCK_NAME(sysctl_resource_uart3, CLK_SRC_GROUP_COMMON, clock_node_uart3),
122     clock_uart4 = MAKE_CLOCK_NAME(sysctl_resource_uart4, CLK_SRC_GROUP_COMMON, clock_node_uart4),
123     clock_uart5 = MAKE_CLOCK_NAME(sysctl_resource_uart5, CLK_SRC_GROUP_COMMON, clock_node_uart5),
124     clock_uart6 = MAKE_CLOCK_NAME(sysctl_resource_uart6, CLK_SRC_GROUP_COMMON, clock_node_uart6),
125     clock_uart7 = MAKE_CLOCK_NAME(sysctl_resource_uart7, CLK_SRC_GROUP_COMMON, clock_node_uart7),
126     clock_xpi0 = MAKE_CLOCK_NAME(sysctl_resource_xpi0, CLK_SRC_GROUP_COMMON, clock_node_xpi0),
127     clock_ref0 = MAKE_CLOCK_NAME(sysctl_resource_ref0, CLK_SRC_GROUP_COMMON, clock_node_ref0),
128     clock_ref1 = MAKE_CLOCK_NAME(sysctl_resource_ref1, CLK_SRC_GROUP_COMMON, clock_node_ref1),
129 
130     clock_ahb = MAKE_CLOCK_NAME(RESOURCE_SHARED_CPU0, CLK_SRC_GROUP_AHB, clock_node_ahb),
131 
132     clock_watchdog0 = MAKE_CLOCK_NAME(sysctl_resource_wdg0, CLK_SRC_GROUP_EWDG, 0),
133     clock_watchdog1 = MAKE_CLOCK_NAME(sysctl_resource_wdg1, CLK_SRC_GROUP_EWDG, 1),
134     clock_pwdg = MAKE_CLOCK_NAME(RESOURCE_INVALID, CLK_SRC_GROUP_PEWDG, 0),
135 
136     clock_lmm0 = MAKE_CLOCK_NAME(sysctl_resource_lmm0, CLK_SRC_GROUP_CPU0, 0),
137 
138     clock_mbx0 = MAKE_CLOCK_NAME(sysctl_resource_mbx0, CLK_SRC_GROUP_AHB, 0),
139     clock_crc0 = MAKE_CLOCK_NAME(sysctl_resource_crc0, CLK_SRC_GROUP_AHB, 1),
140     clock_acmp = MAKE_CLOCK_NAME(sysctl_resource_acmp, CLK_SRC_GROUP_AHB, 2),
141     clock_opa0 = MAKE_CLOCK_NAME(sysctl_resource_opa0, CLK_SRC_GROUP_AHB, 3),
142     clock_opa1 = MAKE_CLOCK_NAME(sysctl_resource_opa1, CLK_SRC_GROUP_AHB, 4),
143     clock_mot0 = MAKE_CLOCK_NAME(sysctl_resource_mot0, CLK_SRC_GROUP_AHB, 5),
144     clock_rng = MAKE_CLOCK_NAME(sysctl_resource_rng0, CLK_SRC_GROUP_AHB, 6),
145     clock_sdp = MAKE_CLOCK_NAME(sysctl_resource_sdp0, CLK_SRC_GROUP_AHB, 7),
146     clock_kman = MAKE_CLOCK_NAME(sysctl_resource_kman, CLK_SRC_GROUP_AHB, 8),
147     clock_gpio = MAKE_CLOCK_NAME(sysctl_resource_gpio, CLK_SRC_GROUP_AHB, 9),
148     clock_hdma = MAKE_CLOCK_NAME(sysctl_resource_hdma, CLK_SRC_GROUP_AHB, 10),
149     clock_rom = MAKE_CLOCK_NAME(sysctl_resource_rom0, CLK_SRC_GROUP_AHB, 11),
150     clock_tsns = MAKE_CLOCK_NAME(sysctl_resource_tsns, CLK_SRC_GROUP_AHB, 12),
151     clock_usb0 = MAKE_CLOCK_NAME(sysctl_resource_usb0, CLK_SRC_GROUP_AHB, 13),
152     clock_ptpc = MAKE_CLOCK_NAME(sysctl_resource_ptpc, CLK_SRC_GROUP_AHB, 14),
153 
154     clock_ptmr = MAKE_CLOCK_NAME(RESOURCE_INVALID, CLK_SRC_GROUP_PMIC, 0),
155     clock_puart = MAKE_CLOCK_NAME(RESOURCE_INVALID, CLK_SRC_GROUP_PMIC, 1),
156     clock_pgpio = MAKE_CLOCK_NAME(RESOURCE_INVALID, CLK_SRC_GROUP_PMIC, 2),
157 
158     /* For ADC, there are 2-stage clock source and divider configurations */
159     clock_ana0 = MAKE_CLOCK_NAME(RESOURCE_INVALID, CLK_SRC_GROUP_COMMON, clock_node_ana0),
160     clock_ana1 = MAKE_CLOCK_NAME(RESOURCE_INVALID, CLK_SRC_GROUP_COMMON, clock_node_ana1),
161     clock_adc0 = MAKE_CLOCK_NAME(sysctl_resource_adc0, CLK_SRC_GROUP_ADC, 0),
162     clock_adc1 = MAKE_CLOCK_NAME(sysctl_resource_adc1, CLK_SRC_GROUP_ADC, 1),
163 
164     /* For DAC, there are 2-stage clock source and divider configurations */
165     clock_ana2 = MAKE_CLOCK_NAME(RESOURCE_INVALID, CLK_SRC_GROUP_COMMON, clock_node_ana2),
166     clock_ana3 = MAKE_CLOCK_NAME(RESOURCE_INVALID, CLK_SRC_GROUP_COMMON, clock_node_ana3),
167     clock_dac0 = MAKE_CLOCK_NAME(sysctl_resource_dac0, CLK_SRC_GROUP_DAC, 0),
168     clock_dac1 = MAKE_CLOCK_NAME(sysctl_resource_dac1, CLK_SRC_GROUP_DAC, 1),
169 
170     /* Clock sources */
171     clk_osc0clk0 = MAKE_CLOCK_NAME(sysctl_resource_xtal, CLK_SRC_GROUP_SRC, 0),
172     clk_pll0clk0 = MAKE_CLOCK_NAME(sysctl_resource_clk0_pll0, CLK_SRC_GROUP_SRC, 1),
173     clk_pll0clk1 = MAKE_CLOCK_NAME(sysctl_resource_clk1_pll0, CLK_SRC_GROUP_SRC, 2),
174     clk_pll0clk2 = MAKE_CLOCK_NAME(sysctl_resource_clk2_pll0, CLK_SRC_GROUP_SRC, 3),
175     clk_pll1clk0 = MAKE_CLOCK_NAME(sysctl_resource_clk0_pll1, CLK_SRC_GROUP_SRC, 4),
176     clk_pll1clk1 = MAKE_CLOCK_NAME(sysctl_resource_clk1_pll1, CLK_SRC_GROUP_SRC, 5),
177     clk_pll1clk2 = MAKE_CLOCK_NAME(sysctl_resource_clk2_pll1, CLK_SRC_GROUP_SRC, 6),
178     clk_pll1clk3 = MAKE_CLOCK_NAME(sysctl_resource_clk3_pll1, CLK_SRC_GROUP_SRC, 7),
179 } clock_name_t;
180 
181 extern uint32_t hpm_core_clock;
182 
183 #ifdef __cplusplus
184 extern "C" {
185 #endif
186 
187 /**
188  * @brief Get specified IP frequency
189  * @param[in] clock_name IP clock name
190  *
191  * @return IP clock frequency in Hz
192  */
193 uint32_t clock_get_frequency(clock_name_t clock_name);
194 
195 /**
196  * @brief Get Clock frequency for selected clock source
197  * @param [in] source clock source
198  * @return clock frequency for selected clock source
199  */
200 uint32_t get_frequency_for_source(clock_source_t source);
201 
202 /**
203  * @brief Get the IP clock source
204  *        Note: This API return the direct clock source
205  * @param [in] clock_name clock name
206  * @return IP clock source
207  */
208 clk_src_t clock_get_source(clock_name_t clock_name);
209 
210 /**
211  * @brief Get the IP clock divider
212  *        Note:This API return the direct clock divider
213  * @param [in] clock_name clock name
214  * @return IP clock divider
215  */
216 uint32_t clock_get_divider(clock_name_t clock_name);
217 
218 /**
219  * @brief Set ADC clock source
220  * @param[in] clock_name ADC clock name
221  * @param[in] src ADC clock source
222  *
223  * @return #status_success Setting ADC clock source is successful
224  *         #status_clk_invalid Invalid ADC clock
225  *         #status_clk_src_invalid Invalid ADC clock source
226  */
227 hpm_stat_t clock_set_adc_source(clock_name_t clock_name, clk_src_t src);
228 
229 /**
230  * @brief Set DAC clock source
231  * @param[in] clock_name DAC clock name
232  * @param[in] src DAC clock source
233  *
234  * @return #status_success Setting DAC clock source is successful
235  *         #status_clk_invalid Invalid DAC clock
236  *         #status_clk_src_invalid Invalid DAC clock source
237  */
238 hpm_stat_t clock_set_dac_source(clock_name_t clock_name, clk_src_t src);
239 
240 /**
241  * @brief Set the WDG clock source
242  * @param [in] clock_name WDG clock name
243  * @param [in] src WDG clock source
244  *
245  * @retval status_success Setting WDG clock source is successful
246  * @retval status_invalid_argument Invalid WDG or invalid clock source
247  */
248 hpm_stat_t clock_set_wdg_source(clock_name_t clock_name, clk_src_t src);
249 
250 /**
251  * @brief Set the IP clock source and divider
252  * @param[in] clock_name clock name
253  * @param[in] src clock source
254  * @param[in] div clock divider, valid range (1 - 256)
255  *
256  * @return #status_success Setting Clock source and divider is successful.
257  *         #status_clk_src_invalid clock source is invalid.
258  *         #status_clk_fixed clock source and divider is a fixed value
259  *         #status_clk_shared_ahb Clock is shared with the AHB clock
260  *         #status_clk_shared_axi0 Clock is shared with the AXI0 clock
261  *         #status_clk_shared_axi1 CLock is shared with the AXI1 clock
262  *         #status_clk_shared_axi2 Clock is shared with the AXI2 clock
263  *         #status_clk_shared_cpu0 Clock is shared with the CPU0 clock
264  *         #status_clk_shared_cpu1 Clock is shared with the CPU1 clock
265  */
266 hpm_stat_t clock_set_source_divider(clock_name_t clock_name, clk_src_t src, uint32_t div);
267 
268 /**
269  * @brief Enable IP clock
270  * @param[in] clock_name IP clock name
271  */
272 void clock_enable(clock_name_t clock_name);
273 
274 /**
275  * @brief Disable IP clock
276  * @param[in] clock_name IP clock name
277  */
278 void clock_disable(clock_name_t clock_name);
279 
280 /**
281  * @brief Add IP to specified group
282  * @param[in] clock_name IP clock name
283  * @param[in] group resource group index, valid value: 0/1/2/3
284  */
285 void clock_add_to_group(clock_name_t clock_name, uint32_t group);
286 
287 /**
288  * @brief Remove IP from specified group
289  * @param[in] clock_name IP clock name
290  * @param[in] group resource group index, valid value: 0/1/2/3
291  */
292 void clock_remove_from_group(clock_name_t clock_name, uint32_t group);
293 
294 /**
295  * @brief Check IP in specified group
296  * @param[in] clock_name IP clock name
297  * @param[in] group resource group index, valid value: 0/1/2/3
298  * @return true if in group, false if not in group
299  */
300 bool clock_check_in_group(clock_name_t clock_name, uint32_t group);
301 
302 /**
303  * @brief Disconnect the clock group from specified CPU
304  * @param[in] group clock group index, value value is 0/1/2/3
305  * @param[in] cpu CPU index, valid value is 0/1
306  */
307 void clock_connect_group_to_cpu(uint32_t group, uint32_t cpu);
308 
309 /**
310  * @brief Disconnect the clock group from specified CPU
311  * @param[in] group clock group index, value value is 0/1/2/3
312  * @param[in] cpu CPU index, valid value is 0/1
313  */
314 void clock_disconnect_group_from_cpu(uint32_t group, uint32_t cpu);
315 
316 /**
317  * @brief Delay specified microseconds
318  *
319  * @param [in] us expected delay interval in microseconds
320  */
321 void clock_cpu_delay_us(uint32_t us);
322 
323 /**
324  * @brief Delay specified milliseconds
325  *
326  * @param [in] ms expected delay interval in milliseconds
327  */
328 void clock_cpu_delay_ms(uint32_t ms);
329 
330 /**
331  * @brief Update the Core clock frequency
332  */
333 void clock_update_core_clock(void);
334 
335 
336 #ifdef __cplusplus
337 }
338 #endif
339 
340 #endif /* HPM_CLOCK_DRV_H */
341