1 /* SPDX-License-Identifier: BSD-3-Clause */
2 /*
3  * Copyright (c) 2020-2021 Rockchip Electronics Co., Ltd.
4  */
5 
6 #include "hal_base.h"
7 
8 #if defined(RKMCU_RK2108) && defined(HAL_CRU_MODULE_ENABLED)
9 
10 /** @addtogroup RK_HAL_Driver
11  *  @{
12  */
13 
14 /** @addtogroup CRU
15  *  @{
16  */
17 
18 /** @defgroup CRU_Private_Definition Private Definition
19  *  @{
20  */
21 /********************* Private MACRO Definition ******************************/
22 #define DCLK_LCDC_PLL_LIMIT_FREQ 800 * 1000000
23 #define CRU_AS_CFG_VAL2          0x1
24 #define CRU_AS_CNT_MSK           0xFFFF
25 
26 /********************* Private Structure Definition **************************/
27 
28 static struct PLL_CONFIG PLL_TABLE[] = {
29     /* _mhz, _refDiv, _fbDiv, _postdDv1, _postDiv2, _dsmpd, _frac */
30     RK_PLL_RATE(1188000000, 2, 99, 1, 1, 1, 0),
31     RK_PLL_RATE(600000000, 3, 75, 1, 1, 1, 0),
32     RK_PLL_RATE(282240000, 1, 35, 3, 1, 0, 4697620),
33     RK_PLL_RATE(245760000, 1, 40, 4, 1, 0, 16106127),
34     { 0 /* sentinel */ },
35 };
36 
37 static uint32_t s_gpllFreq;
38 static uint32_t s_cpllFreq;
39 
40 static struct PLL_SETUP GPLL = {
41     .conOffset0 = &(CRU->GPLL_CON[0]),
42     .conOffset1 = &(CRU->GPLL_CON[1]),
43     .conOffset2 = &(CRU->GPLL_CON[2]),
44     .modeOffset = &(CRU->CRU_MODE_CON00),
45     .modeShift = 0,
46     .lockShift = 10,
47     .modeMask = 0x3 << 0,
48     .rateTable = PLL_TABLE,
49 };
50 
51 static struct PLL_SETUP CPLL = {
52     .conOffset0 = &(CRU->CPLL_CON[0]),
53     .conOffset1 = &(CRU->CPLL_CON[1]),
54     .conOffset2 = &(CRU->CPLL_CON[2]),
55     .modeOffset = &(CRU->CRU_MODE_CON00),
56     .modeShift = 2,
57     .lockShift = 10,
58     .modeMask = 0x3 << 2,
59     .rateTable = PLL_TABLE,
60 };
61 /********************* Private Variable Definition ***************************/
62 
63 /********************* Private Function Definition ***************************/
64 #ifdef HAL_CRU_DCG_FEATURE_ENABLED
CRU_DcgConfig(uint8_t ch,uint8_t func,uint32_t val1,uint32_t val2)65 static void CRU_DcgConfig(uint8_t ch, uint8_t func, uint32_t val1, uint32_t val2)
66 {
67     HAL_ASSERT(ch < 2);
68 
69     switch (func) {
70     case 1: /* cfg en */
71         CRU->DCG_CON[ch][4] = VAL_MASK_WE(CRU_DCG0_CON4_CFG_EN_MASK,
72                                           val1 << CRU_DCG0_CON4_CFG_EN_SHIFT);
73         break;
74     case 2: /* period cnt */
75         CRU->DCG_CON[ch][0] = val1;
76         CRU->DCG_CON[ch][1] = val2;
77         break;
78     case 3: /* period cnt */
79         CRU->DCG_CON[ch][2] = val1;
80         CRU->DCG_CON[ch][3] = val2;
81         break;
82     case 4: /* step */
83         CRU->DCG_CON[ch][4] = VAL_MASK_WE(CRU_DCG0_CON4_CFG_STEP1_MASK,
84                                           val1 << CRU_DCG0_CON4_CFG_STEP1_SHIFT);
85         CRU->DCG_CON[ch][4] = VAL_MASK_WE(CRU_DCG0_CON4_CFG_STEP2_MASK,
86                                           val2 << CRU_DCG0_CON4_CFG_STEP2_SHIFT);
87         break;
88     case 5: /* limit */
89         CRU->DCG_CON[ch][5] = VAL_MASK_WE(CRU_DCG0_CON5_CFG_LMT_MASK,
90                                           val1 << CRU_DCG0_CON5_CFG_LMT_SHIFT);
91         break;
92     default:
93         break;
94     }
95 }
96 #endif
97 
98 #ifdef HAL_CRU_AS_FEATURE_ENABLED
CRU_AsConfig(uint8_t ch,uint32_t val1,uint32_t val2)99 static void CRU_AsConfig(uint8_t ch, uint32_t val1, uint32_t val2)
100 {
101     HAL_ASSERT(ch < 5);
102     CRU->AS_CON[ch][1] = VAL_MASK_WE(CRU_AS0_CON1_AS_CTRL_MASK |
103                                      CRU_AS0_CON1_AS_CFG_MASK |
104                                      CRU_AS0_CON1_ASS_EN_MASK |
105                                      CRU_AS0_CON1_AS_EN_MASK,
106                                      val1 << CRU_AS0_CON1_AS_CTRL_SHIFT |
107                                      val2 << CRU_AS0_CON1_AS_CFG_SHIFT);
108 }
109 
CRU_AsCntConfig(uint8_t ch,uint32_t val1,uint32_t val2)110 static void CRU_AsCntConfig(uint8_t ch, uint32_t val1, uint32_t val2)
111 {
112     HAL_ASSERT(ch < 5);
113 
114     if (val1 >= CRU_AS_CNT_MSK) {
115         val1 = CRU->AS_CON[ch][0] & CRU_AS_CNT_MSK;
116     }
117 
118     if (val2 >= CRU_AS_CNT_MSK) {
119         val2 = (CRU->AS_CON[ch][0] >> 16) & CRU_AS_CNT_MSK;
120     }
121 
122     CRU->AS_CON[ch][0] = val1 | (val2 << 16);
123 }
124 #endif
125 /** @} */
126 /********************* Public Function Definition ****************************/
127 
128 /** @defgroup CRU_Exported_Functions_Group5 Other Functions
129  *  @{
130  */
131 
132 #ifdef HAL_CRU_AS_FEATURE_ENABLED
HAL_CRU_AsEnable(uint8_t ch,uint8_t en)133 void HAL_CRU_AsEnable(uint8_t ch, uint8_t en)
134 {
135     HAL_ASSERT(ch < 5);
136 
137     if (en) {
138         CRU->AS_CON[ch][1] = VAL_MASK_WE(CRU_AS0_CON1_AS_EN_MASK |
139                                          CRU_AS0_CON1_ASS_EN_MASK,
140                                          CRU_AS0_CON1_AS_EN_MASK |
141                                          CRU_AS0_CON1_ASS_EN_MASK);
142     } else {
143         CRU->AS_CON[ch][1] = VAL_MASK_WE(CRU_AS0_CON1_AS_EN_MASK |
144                                          CRU_AS0_CON1_ASS_EN_MASK, 0);
145     }
146 }
147 
HAL_CRU_AsInit(void)148 void HAL_CRU_AsInit(void)
149 {
150     CRU_AsConfig(0, 0x77, CRU_AS_CFG_VAL2);
151     CRU_AsCntConfig(0, 0x20, 0x18);
152 
153     CRU_AsConfig(1, 0x99, CRU_AS_CFG_VAL2);
154     CRU_AsCntConfig(1, 0x20, 0x18);
155 
156     CRU_AsConfig(2, 0x1, CRU_AS_CFG_VAL2);
157     CRU_AsCntConfig(2, 0x20, 0x18);
158 
159     CRU_AsConfig(3, 0x99, CRU_AS_CFG_VAL2);
160     CRU_AsCntConfig(3, 0x20, 0x18);
161 
162     CRU_AsConfig(4, 0x99, CRU_AS_CFG_VAL2);
163     CRU_AsCntConfig(4, 0x20, 0x18);
164 
165     HAL_CRU_AsEnable(1, 1);
166     HAL_CRU_AsEnable(2, 1);
167     HAL_CRU_AsEnable(3, 1);
168     HAL_CRU_AsEnable(4, 1);
169 }
170 #endif
171 
172 /**
173  * @brief vop dclk enable.
174  * @param  gateId: gate id
175  * @return HAL_Status.
176  * @attention these APIs allow direct use in the HAL layer.
177  */
HAL_CRU_VopDclkEnable(uint32_t gateId)178 HAL_Status HAL_CRU_VopDclkEnable(uint32_t gateId)
179 {
180     HAL_Status ret = HAL_OK;
181 
182     HAL_CRU_ClkEnable(gateId);
183 
184     return ret;
185 }
186 
187 /**
188  * @brief vop dclk disable.
189  * @param  gateId: gate id
190  * @return HAL_Status.
191  * @attention these APIs allow direct use in the HAL layer.
192  */
HAL_CRU_VopDclkDisable(uint32_t gateId)193 HAL_Status HAL_CRU_VopDclkDisable(uint32_t gateId)
194 {
195     HAL_Status ret = HAL_OK;
196 
197     HAL_CRU_ClkDisable(gateId);
198 
199     return ret;
200 }
201 
202 /**
203  * @brief Get frac clk freq.
204  * @param  clockName: CLOCK_Name id
205  * @return clk rate.
206  * How to calculate the Frac clk divider:
207  *     numerator is frac register[31:16]
208  *     denominator is frac register[15:0]
209  *     clk rate = pRate * numerator / denominator
210  *     for a better jitter, pRate > 20 * rate
211  */
HAL_CRU_ClkFracGetFreq(eCLOCK_Name clockName)212 static uint32_t HAL_CRU_ClkFracGetFreq(eCLOCK_Name clockName)
213 {
214     uint32_t freq = 0;
215     uint32_t muxSrc = 0, mux = CLK_GET_MUX(clockName);
216     uint32_t divSrc = 0, divFrac = 0;
217     uint32_t n, m, pRate;
218 
219     switch (clockName) {
220     case CLK_UART0:
221         muxSrc = CLK_GET_MUX(CLK_UART0_SRC);
222         divSrc = CLK_GET_DIV(CLK_UART0_SRC);
223         divFrac = CLK_GET_DIV(CLK_UART0_FRAC);
224         break;
225     case CLK_UART1:
226         muxSrc = CLK_GET_MUX(CLK_UART1_SRC);
227         divSrc = CLK_GET_DIV(CLK_UART1_SRC);
228         divFrac = CLK_GET_DIV(CLK_UART1_FRAC);
229         break;
230     case CLK_UART2:
231         muxSrc = CLK_GET_MUX(CLK_UART2_SRC);
232         divSrc = CLK_GET_DIV(CLK_UART2_SRC);
233         divFrac = CLK_GET_DIV(CLK_UART2_FRAC);
234         break;
235     case I2S_MCLKOUT:
236         muxSrc = CLK_GET_MUX(CLK_I2S8CH_SRC);
237         divSrc = CLK_GET_DIV(CLK_I2S8CH_SRC);
238         divFrac = CLK_GET_DIV(CLK_I2S8CH_FRAC);
239         mux = CLK_GET_MUX(MCLK_I2S8CH);
240         break;
241     case I2S1_MCLKOUT:
242         muxSrc = CLK_GET_MUX(CLK_I2S1_8CH_SRC);
243         divSrc = CLK_GET_DIV(CLK_I2S1_8CH_SRC);
244         divFrac = CLK_GET_DIV(CLK_I2S1_8CH_FRAC);
245         mux = CLK_GET_MUX(MCLK_I2S1_8CH);
246         break;
247     case CLK_AUDPWM:
248         muxSrc = CLK_GET_MUX(CLK_AUDPWM_SRC);
249         divSrc = CLK_GET_DIV(CLK_AUDPWM_SRC);
250         divFrac = CLK_GET_DIV(CLK_AUDPWM_FRAC);
251         break;
252     case CLK_32K:
253         divFrac = CLK_GET_DIV(CLK_32K);
254         break;
255     default:
256 
257         return 0;
258     }
259 
260     n = (CRU->CRU_CLKSEL_CON[CLK_DIV_GET_REG_OFFSET(divFrac)] & 0xffff0000) >> 16;
261     m = CRU->CRU_CLKSEL_CON[CLK_DIV_GET_REG_OFFSET(divFrac)] & 0x0000ffff;
262 
263     switch (clockName) {
264     case CLK_32K:
265         pRate = PLL_INPUT_OSC_RATE;
266         freq = (pRate / m) * n;
267         break;
268     case CLK_AUDPWM:
269         if (HAL_CRU_ClkGetMux(mux) == 0) {
270             freq = s_gpllFreq / HAL_CRU_ClkGetDiv(divSrc);
271         } else if (HAL_CRU_ClkGetMux(mux) == 1) {
272             freq = (s_gpllFreq / m) * n;
273         }
274         break;
275     default:
276         if (HAL_CRU_ClkGetMux(muxSrc)) {
277             pRate = s_cpllFreq / HAL_CRU_ClkGetDiv(divSrc);
278         } else {
279             pRate = s_gpllFreq / HAL_CRU_ClkGetDiv(divSrc);
280         }
281 
282         if (HAL_CRU_ClkGetMux(mux) == 0) {
283             freq = pRate;
284         } else if (HAL_CRU_ClkGetMux(mux) == 1) {
285             freq = (pRate / m) * n;
286         } else if (HAL_CRU_ClkGetMux(mux) == 2) {
287             freq = PLL_INPUT_OSC_RATE;
288         }
289         break;
290     }
291 
292     return freq;
293 }
294 
295 /**
296  * @brief Set frac clk freq.
297  * @param  clockName: CLOCK_Name id.
298  * @param  rate: clk set rate
299  * @return HAL_Status.
300  * How to calculate the Frac clk divider:
301  *     if pRate > 20 * rate, select frac divider
302  *     else select normal divider, but the clk rate may be not accurate
303  */
HAL_CRU_ClkFracSetFreq(eCLOCK_Name clockName,uint32_t rate)304 static HAL_Status HAL_CRU_ClkFracSetFreq(eCLOCK_Name clockName, uint32_t rate)
305 {
306     uint32_t muxSrc, mux = CLK_GET_MUX(clockName), muxOut = 0;
307     uint32_t divSrc, divFrac;
308     uint32_t n = 0, m = 0, pRate = s_gpllFreq;
309     uint32_t gateId, fracGateId;
310 
311     switch (clockName) {
312     case CLK_UART0:
313         muxSrc = CLK_GET_MUX(CLK_UART0_SRC);
314         divSrc = CLK_GET_DIV(CLK_UART0_SRC);
315         divFrac = CLK_GET_DIV(CLK_UART0_FRAC);
316         gateId = CLK_UART0_GATE;
317         fracGateId = CLK_UART0_FRAC_GATE;
318         break;
319     case CLK_UART1:
320         muxSrc = CLK_GET_MUX(CLK_UART1_SRC);
321         divSrc = CLK_GET_DIV(CLK_UART1_SRC);
322         divFrac = CLK_GET_DIV(CLK_UART1_FRAC);
323         gateId = CLK_UART1_GATE;
324         fracGateId = CLK_UART1_FRAC_GATE;
325         break;
326     case CLK_UART2:
327         muxSrc = CLK_GET_MUX(CLK_UART2_SRC);
328         divSrc = CLK_GET_DIV(CLK_UART2_SRC);
329         divFrac = CLK_GET_DIV(CLK_UART2_FRAC);
330         gateId = CLK_UART2_GATE;
331         fracGateId = CLK_UART2_FRAC_GATE;
332         break;
333     case I2S_MCLKOUT:
334         muxSrc = CLK_GET_MUX(CLK_I2S8CH_SRC);
335         divSrc = CLK_GET_DIV(CLK_I2S8CH_SRC);
336         divFrac = CLK_GET_DIV(CLK_I2S8CH_FRAC);
337         mux = CLK_GET_MUX(MCLK_I2S8CH);
338         muxOut = CLK_GET_MUX(I2S_MCLKOUT);
339         gateId = CLK_I2S8CH_GATE;
340         fracGateId = CLK_I2S8CH_FRAC_GATE;
341         break;
342     case I2S1_MCLKOUT:
343         muxSrc = CLK_GET_MUX(CLK_I2S1_8CH_SRC);
344         divSrc = CLK_GET_DIV(CLK_I2S1_8CH_SRC);
345         divFrac = CLK_GET_DIV(CLK_I2S1_8CH_FRAC);
346         mux = CLK_GET_MUX(MCLK_I2S1_8CH);
347         muxOut = CLK_GET_MUX(I2S1_MCLKOUT);
348         gateId = CLK_I2S1_8CH_GATE;
349         fracGateId = CLK_I2S1_8CH_FRAC_GATE;
350         break;
351     case CLK_AUDPWM:
352         muxSrc = CLK_GET_MUX(CLK_AUDPWM_SRC);
353         divSrc = CLK_GET_DIV(CLK_AUDPWM_SRC);
354         divFrac = CLK_GET_DIV(CLK_AUDPWM_FRAC);
355         pRate = s_gpllFreq;
356         gateId = CLK_AUDPWM_DF_GATE;
357         fracGateId = CLK_AUDPWM_FRAC_GATE;
358         break;
359     case CLK_32K:
360         divFrac = CLK_GET_DIV(CLK_32K);
361         pRate = PLL_INPUT_OSC_RATE;
362         break;
363     default:
364 
365         return HAL_INVAL;
366     }
367 
368     switch (clockName) {
369     case CLK_UART0:
370     case CLK_UART1:
371     case CLK_UART2:
372         HAL_CRU_ClkEnable(gateId);
373         HAL_CRU_ClkEnable(fracGateId);
374         if (PLL_INPUT_OSC_RATE == rate) {
375             HAL_CRU_ClkSetMux(mux, 2);
376             HAL_CRU_ClkDisable(gateId);
377         } else if ((!(s_gpllFreq % rate)) && ((s_gpllFreq / rate) < 31)) {
378             HAL_CRU_ClkSetDiv(divSrc, s_gpllFreq / rate);
379             HAL_CRU_ClkSetMux(muxSrc, 0);
380             HAL_CRU_ClkSetMux(mux, 0);
381             HAL_CRU_ClkDisable(fracGateId);
382         } else if ((!(s_cpllFreq % rate)) && ((s_cpllFreq / rate) < 31)) {
383             HAL_CRU_ClkSetDiv(divSrc, s_cpllFreq / rate);
384             HAL_CRU_ClkSetMux(muxSrc, 1);
385             HAL_CRU_ClkSetMux(mux, 0);
386             HAL_CRU_ClkDisable(fracGateId);
387         } else {
388             HAL_CRU_FracdivGetConfig(rate, pRate, &n, &m);
389             HAL_CRU_ClkSetDiv(divSrc, 1);
390             HAL_CRU_ClkSetMux(muxSrc, 0);
391             CRU->CRU_CLKSEL_CON[CLK_DIV_GET_REG_OFFSET(divFrac)] = (n << 16) | m;
392             HAL_CRU_ClkSetMux(mux, 1);
393         }
394 
395         return HAL_OK;
396     case I2S_MCLKOUT:
397     case I2S1_MCLKOUT:
398     case CLK_AUDPWM:
399         HAL_CRU_ClkEnable(gateId);
400         HAL_CRU_ClkEnable(fracGateId);
401         if (PLL_INPUT_OSC_RATE == rate) {
402             HAL_CRU_ClkSetMux(mux, 2);
403             HAL_CRU_ClkDisable(gateId);
404         } else if ((!(s_cpllFreq % rate)) && ((s_cpllFreq / rate) < 31)) {
405             HAL_CRU_ClkSetDiv(divSrc, s_cpllFreq / rate);
406             HAL_CRU_ClkSetMux(muxSrc, 1);
407             HAL_CRU_ClkSetMux(mux, 0);
408             HAL_CRU_ClkDisable(fracGateId);
409         } else {
410             HAL_CRU_FracdivGetConfig(rate, s_cpllFreq, &n, &m);
411             HAL_CRU_ClkSetDiv(divSrc, 1);
412             HAL_CRU_ClkSetMux(muxSrc, 1);
413             CRU->CRU_CLKSEL_CON[CLK_DIV_GET_REG_OFFSET(divFrac)] = (n << 16) | m;
414             HAL_CRU_ClkSetMux(mux, 1);
415         }
416         if (muxOut) {
417             HAL_CRU_ClkSetMux(muxOut, 0);
418         }
419 
420         return HAL_OK;
421     case CLK_32K:
422         HAL_CRU_FracdivGetConfig(rate, PLL_INPUT_OSC_RATE, &n, &m);
423         CRU->CRU_CLKSEL_CON[CLK_DIV_GET_REG_OFFSET(divFrac)] = (n << 16) | m;
424 
425         return HAL_OK;
426     default:
427 
428         return HAL_INVAL;
429     }
430 }
431 
432 /**
433  * @brief Get Usb clk freq.
434  * @param  clockName: CLOCK_Name id
435  * @return clk rate.
436  * How to calculate the Frac clk divider:
437  *     numerator is frac register[31:16]
438  *     denominator is frac register[15:0]
439  *     clk rate = pRate * numerator / denominator
440  */
HAL_CRU_ClkUsbGetFreq(eCLOCK_Name clockName)441 static uint32_t HAL_CRU_ClkUsbGetFreq(eCLOCK_Name clockName)
442 {
443     uint32_t freq = 0;
444     uint32_t muxSrc, mux = CLK_GET_MUX(clockName);
445     uint32_t divFrac;
446     uint32_t n, m, pRate;
447 
448     switch (clockName) {
449     case CLK_USB2PHY_REF:
450         muxSrc = CLK_GET_MUX(CLK_USB2PHY_REF_FRAC);
451         divFrac = CLK_GET_DIV(CLK_USB2PHY_REF_FRAC);
452         break;
453     case CLK_DPHY_REF:
454         muxSrc = CLK_GET_MUX(CLK_DPHY_REF_FRAC);
455         divFrac = CLK_GET_DIV(CLK_DPHY_REF_FRAC);
456         break;
457     default:
458 
459         return 0;
460     }
461     n = (CRU->CRU_CLKSEL_CON[CLK_DIV_GET_REG_OFFSET(divFrac)] & 0xffff0000) >> 16;
462     m = CRU->CRU_CLKSEL_CON[CLK_DIV_GET_REG_OFFSET(divFrac)] & 0x0000ffff;
463 
464     if (HAL_CRU_ClkGetMux(muxSrc)) {
465         pRate = s_cpllFreq;
466     } else {
467         pRate = s_gpllFreq;
468     }
469 
470     if (HAL_CRU_ClkGetMux(mux) == 0) {
471         freq = PLL_INPUT_OSC_RATE;
472     } else if (HAL_CRU_ClkGetMux(mux) == 1) {
473         freq = (pRate / m) * n;
474     }
475 
476     return freq;
477 }
478 
479 /**
480  * @brief Set usb clk freq.
481  * @param  clockName: CLOCK_Name id.
482  * @param  rate: clk set rate
483  * @return HAL_Status.
484  * How to calculate the Frac clk divider:
485  *     if rate is inpust osc rate, select input osc
486  *     else select ifrac divider
487  */
HAL_CRU_ClkUsbSetFreq(eCLOCK_Name clockName,uint32_t rate)488 static HAL_Status HAL_CRU_ClkUsbSetFreq(eCLOCK_Name clockName, uint32_t rate)
489 {
490     uint32_t muxSrc, mux = CLK_GET_MUX(clockName);
491     uint32_t divFrac;
492     uint32_t n = 0, m = 0, pRate = s_gpllFreq;
493 
494     switch (clockName) {
495     case CLK_USB2PHY_REF:
496         muxSrc = CLK_GET_MUX(CLK_USB2PHY_REF_FRAC);
497         divFrac = CLK_GET_DIV(CLK_USB2PHY_REF_FRAC);
498         break;
499     case CLK_DPHY_REF:
500         muxSrc = CLK_GET_MUX(CLK_DPHY_REF_FRAC);
501         divFrac = CLK_GET_DIV(CLK_DPHY_REF_FRAC);
502         break;
503     default:
504 
505         return HAL_INVAL;
506     }
507 
508     if (rate == PLL_INPUT_OSC_RATE) {
509         HAL_CRU_ClkSetMux(mux, 0);
510     } else {
511         HAL_CRU_FracdivGetConfig(rate, pRate, &n, &m);
512         HAL_CRU_ClkSetMux(muxSrc, 0);
513         CRU->CRU_CLKSEL_CON[CLK_DIV_GET_REG_OFFSET(divFrac)] = (n << 16) | m;
514         HAL_CRU_ClkSetMux(mux, 1);
515     }
516 
517     return HAL_OK;
518 }
519 
520 /**
521  * @brief Get clk freq.
522  * @param  clockName: CLOCK_Name id.
523  * @return rate.
524  * @attention these APIs allow direct use in the HAL layer.
525  */
HAL_CRU_ClkGetFreq(eCLOCK_Name clockName)526 uint32_t HAL_CRU_ClkGetFreq(eCLOCK_Name clockName)
527 {
528     uint32_t freq;
529     uint32_t clkMux = CLK_GET_MUX(clockName), mux = 0;
530     uint32_t clkDiv = CLK_GET_DIV(clockName);
531     uint32_t pRate = s_gpllFreq;
532 
533     if (!s_gpllFreq) {
534         s_gpllFreq = HAL_CRU_GetPllFreq(&GPLL);
535     }
536     if (!s_cpllFreq) {
537         s_cpllFreq = HAL_CRU_GetPllFreq(&CPLL);
538     }
539 
540     switch (clockName) {
541     case PLL_GPLL:
542         freq = HAL_CRU_GetPllFreq(&GPLL);
543         s_gpllFreq = freq;
544 
545         return freq;
546     case PLL_CPLL:
547         freq = HAL_CRU_GetPllFreq(&CPLL);
548         s_cpllFreq = freq;
549 
550         return freq;
551     case DCLK_VOP_S:
552         if (HAL_CRU_ClkGetMux(clkMux)) {
553             pRate = s_cpllFreq;
554         }
555 
556         freq = pRate / HAL_CRU_ClkGetDiv(clkDiv);
557 
558         return freq;
559     case CLK_UART0:
560     case CLK_UART1:
561     case CLK_UART2:
562     case I2S_MCLKOUT:
563     case I2S1_MCLKOUT:
564     case CLK_AUDPWM:
565     case CLK_32K:
566         freq = HAL_CRU_ClkFracGetFreq(clockName);
567 
568         return freq;
569     case ACLK_DSP:
570     case HCLK_AUDIO:
571     case MCLK_PDM0:
572     case SCLK_SFC_SRC:
573     case SCLK_SFC1_SRC:
574         if (HAL_CRU_ClkGetMux(clkMux)) {
575             pRate = s_cpllFreq;
576         } else {
577             pRate = s_gpllFreq;
578         }
579         break;
580     case CLK_PWM:
581         mux = HAL_CRU_ClkGetMux(clkMux);
582         if (mux) {
583             pRate = PLL_INPUT_OSC_RATE;
584         }
585         break;
586     case CLK_GPIO_DBG0:
587     case CLK_GPIO_DBG1:
588         pRate = PLL_INPUT_OSC_RATE;
589         break;
590     case CLK_USB2PHY_REF:
591     case CLK_DPHY_REF:
592         freq = HAL_CRU_ClkUsbGetFreq(clockName);
593 
594         return freq;
595     case CLK_CIFOUT:
596         mux = HAL_CRU_ClkGetMux(clkMux);
597         if (mux == 2) {
598             pRate = PLL_INPUT_OSC_RATE;
599         }
600         break;
601     default:
602         break;
603     }
604 
605     if ((clkMux == 0) && (clkDiv == 0)) {
606         return 0;
607     }
608 
609     if (clkDiv) {
610         freq = pRate / (HAL_CRU_ClkGetDiv(clkDiv));
611     } else {
612         freq = pRate;
613     }
614 
615     return freq;
616 }
617 
618 /**
619  * @brief Set clk freq.
620  * @param  clockName: CLOCK_Name id.
621  * @param  rate: clk rate.
622  * @return HAL_Status.
623  * @attention these APIs allow direct use in the HAL layer.
624  */
HAL_CRU_ClkSetFreq(eCLOCK_Name clockName,uint32_t rate)625 HAL_Status HAL_CRU_ClkSetFreq(eCLOCK_Name clockName, uint32_t rate)
626 {
627     HAL_Status error = HAL_OK;
628     uint32_t clkMux = CLK_GET_MUX(clockName), mux = 0;
629     uint32_t clkDiv = CLK_GET_DIV(clockName), div = 0;
630     uint32_t pRate = s_gpllFreq;
631 
632     if (!s_gpllFreq) {
633         s_gpllFreq = HAL_CRU_GetPllFreq(&GPLL);
634     }
635     if (!s_cpllFreq) {
636         s_cpllFreq = HAL_CRU_GetPllFreq(&CPLL);
637     }
638 
639     switch (clockName) {
640     case PLL_GPLL:
641         error = HAL_CRU_SetPllFreq(&GPLL, rate);
642         s_gpllFreq = HAL_CRU_GetPllFreq(&GPLL);
643 
644         return error;
645     case PLL_CPLL:
646         error = HAL_CRU_SetPllFreq(&CPLL, rate);
647         s_cpllFreq = HAL_CRU_GetPllFreq(&CPLL);
648 
649         return error;
650     case DCLK_VOP_S:
651         if (!(s_gpllFreq % rate)) {
652             pRate = s_gpllFreq;
653             mux = 0;
654         } else {
655             pRate = s_cpllFreq;
656             mux = 1;
657         }
658         div = HAL_DIV_ROUND_UP(pRate, rate);
659         HAL_CRU_ClkSetMux(clkMux, mux);
660         HAL_CRU_ClkSetDiv(clkDiv, div);
661 
662         return error;
663     case CLK_UART0:
664     case CLK_UART1:
665     case CLK_UART2:
666     case I2S_MCLKOUT:
667     case I2S1_MCLKOUT:
668     case CLK_AUDPWM:
669     case CLK_32K:
670         error = HAL_CRU_ClkFracSetFreq(clockName, rate);
671 
672         return error;
673     case ACLK_DSP:
674     case HCLK_AUDIO:
675     case MCLK_PDM0:
676         error = HAL_CRU_ClkFracSetFreq(clockName, rate);
677         pRate = s_cpllFreq;
678         mux = 1;
679         break;
680     case SCLK_SFC_SRC:
681     case SCLK_SFC1_SRC:
682         if (s_cpllFreq == PLL_INPUT_OSC_RATE) {
683             pRate = s_gpllFreq;
684             mux = 0;
685         } else {
686             pRate = s_cpllFreq;
687             mux = 1;
688         }
689         break;
690     case CLK_PWM:
691         if (rate <= PLL_INPUT_OSC_RATE) {
692             mux = 1;
693             pRate = PLL_INPUT_OSC_RATE;
694         }
695         break;
696     case CLK_GPIO_DBG0:
697     case CLK_GPIO_DBG1:
698         pRate = PLL_INPUT_OSC_RATE;
699         break;
700     case CLK_USB2PHY_REF:
701     case CLK_DPHY_REF:
702         error = HAL_CRU_ClkUsbSetFreq(clockName, rate);
703 
704         return error;
705     case CLK_CIFOUT:
706         if (rate == PLL_INPUT_OSC_RATE) {
707             mux = 2;
708             pRate = PLL_INPUT_OSC_RATE;
709         }
710         break;
711     default:
712         break;
713     }
714 
715     if ((clkMux == 0) && (clkDiv == 0)) {
716         return HAL_INVAL;
717     }
718 
719     div = HAL_DIV_ROUND_UP(pRate, rate);
720     if (clkMux) {
721         HAL_CRU_ClkSetMux(clkMux, mux);
722     }
723     if (clkDiv) {
724         HAL_CRU_ClkSetDiv(clkDiv, div);
725     }
726 
727     if (clockName == HCLK_M4) {
728         HAL_SystemCoreClockUpdate(rate, HAL_SYSTICK_CLKSRC_EXT);
729     }
730 
731     return HAL_OK;
732 }
733 
734 /**
735  * @brief pll output freq Compensation.
736  * @param  clockName: CLOCK_Name id.
737  * @param  ppm: Efforts to compensate.
738  * @return HAL_OK.
739  * @attention these APIs allow direct use in the HAL layer.
740  */
HAL_CRU_PllCompensation(eCLOCK_Name clockName,int ppm)741 HAL_Status HAL_CRU_PllCompensation(eCLOCK_Name clockName, int ppm)
742 {
743     __IO uint32_t *conOffset0, *conOffset2;
744     uint32_t frac, fbdiv;
745     uint64_t fracdiv;
746     long int m, n;
747 
748     if ((ppm > 100) || (ppm < -100)) {
749         return HAL_INVAL;
750     }
751 
752     switch (clockName) {
753     case PLL_GPLL:
754         conOffset0 = &(CRU->GPLL_CON[0]);
755         conOffset2 = &(CRU->GPLL_CON[2]);
756         break;
757     case PLL_CPLL:
758         conOffset0 = &(CRU->CPLL_CON[0]);
759         conOffset2 = &(CRU->CPLL_CON[2]);
760         break;
761     default:
762 
763         return HAL_INVAL;
764     }
765 
766     frac = READ_REG(*conOffset2) & 0xffffff;
767     fbdiv = READ_REG(*conOffset0) & 0xfff;
768     m = frac * ppm;
769     n = ppm << 24;
770 
771     fracdiv = (m / MHZ) + ((n / MHZ) * fbdiv) + frac;
772 
773     if (fracdiv > 0xffffff) {
774         return HAL_INVAL;
775     }
776 
777     WRITE_REG(*conOffset2, (READ_REG(*conOffset2) & 0xff000000) | fracdiv);
778 
779     return HAL_OK;
780 }
781 
782 /**
783  * @brief wdt glbrst enable.
784  * @param  wdtType: wdt reset type.
785  * @return HAL_OK.
786  * @attention these APIs allow direct use in the HAL layer.
787  */
HAL_CRU_WdtGlbRstEnable(eCRU_WdtRstType wdtType)788 HAL_Status HAL_CRU_WdtGlbRstEnable(eCRU_WdtRstType wdtType)
789 {
790     uint32_t mask = 0, val = 0;
791 
792     switch (wdtType) {
793     case GLB_RST_FST_WDT0:
794         mask = CRU_GLB_RST_CON_WDT0_GLBRST_EN_MASK | CRU_GLB_RST_CON_WDT0_FST_GLBRST_EN_MASK;
795         val = (1 << CRU_GLB_RST_CON_WDT0_GLBRST_EN_SHIFT) | (1 << CRU_GLB_RST_CON_WDT0_FST_GLBRST_EN_SHIFT);
796         break;
797     case GLB_RST_FST_WDT1:
798         mask = CRU_GLB_RST_CON_WDT1_GLBRST_EN_MASK | CRU_GLB_RST_CON_WDT1_FST_GLBRST_EN_MASK;
799         val = (1 << CRU_GLB_RST_CON_WDT1_GLBRST_EN_SHIFT) | (1 << CRU_GLB_RST_CON_WDT1_FST_GLBRST_EN_SHIFT);
800         break;
801     case GLB_RST_SND_WDT0:
802         mask = CRU_GLB_RST_CON_WDT0_GLBRST_EN_MASK | CRU_GLB_RST_CON_WDT0_FST_GLBRST_EN_MASK;
803         val = (1 << CRU_GLB_RST_CON_WDT0_GLBRST_EN_SHIFT);
804         break;
805     case GLB_RST_SND_WDT1:
806         mask = CRU_GLB_RST_CON_WDT1_GLBRST_EN_MASK | CRU_GLB_RST_CON_WDT1_FST_GLBRST_EN_MASK;
807         val = (1 << CRU_GLB_RST_CON_WDT1_GLBRST_EN_SHIFT);
808         break;
809     default:
810 
811         return HAL_INVAL;
812     }
813 
814     CRU->GLB_RST_CON = VAL_MASK_WE(mask, val);
815 
816     return HAL_OK;
817 }
818 
819 /** @} */
820 
821 /** @} */
822 
823 /** @} */
824 
825 #endif /* RKMCU_RK2108 && HAL_CRU_MODULE_ENABLED */
826