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