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 #ifdef HAL_CRU_MODULE_ENABLED
9
10 /** @addtogroup RK_HAL_Driver
11 * @{
12 */
13
14 /** @addtogroup CRU
15 * @{
16 */
17
18 /** @defgroup CRU_How_To_Use How To Use
19 * @{
20
21 The CRU driver can be used as follows:
22
23 - Invoke cru functions to set clk rate, enable or disable clk, reset clk in each device.
24 - The gate and soft reset id is include register offset and shift information:
25
26 con_offset: id /16
27 shift: id %16
28
29 - The mux and div id is include register offset, shift, mask information:
30
31 [15:0]: con
32 [23:16]: shift
33 [31:24]: width
34
35 - CRU driver is just responsible for passing simple command data, And
36 the usecount is the user's responsibility. Protection the usecount at the driver layer.
37 - More details refer to APIs' descriptions as below.
38
39 @} */
40
41 /** @defgroup CRU_Private_Definition Private Definition
42 * @{
43 */
44 /********************* Private MACRO Definition ******************************/
45 #if defined(SOC_RV1108)
46 #define PWRDOWN_SHIT 0
47 #define PWRDOWN_MASK 1 << PWRDOWN_SHIT
48 #define PLL_POSTDIV1_SHIFT 8
49 #define PLL_POSTDIV1_MASK 0x7 << PLL_POSTDIV1_SHIFT
50 #define PLL_FBDIV_SHIFT 0
51 #define PLL_FBDIV_MASK 0xfff << PLL_FBDIV_SHIFT
52 #define PLL_POSTDIV2_SHIFT 12
53 #define PLL_POSTDIV2_MASK 0x7 << PLL_POSTDIV2_SHIFT
54 #define PLL_REFDIV_SHIFT 0
55 #define PLL_REFDIV_MASK 0x3f << PLL_REFDIV_SHIFT
56 #define PLL_DSMPD_SHIFT 3
57 #define PLL_DSMPD_MASK 1 << PLL_DSMPD_SHIFT
58 #define PLL_FRAC_SHIFT 0
59 #define PLL_FRAC_MASK 0xffffff << PLL_FRAC_SHIFT
60 #else
61 #define PWRDOWN_SHIT 13
62 #define PWRDOWN_MASK 1 << PWRDOWN_SHIT
63 #define PLL_POSTDIV1_SHIFT 12
64 #define PLL_POSTDIV1_MASK 0x7 << PLL_POSTDIV1_SHIFT
65 #define PLL_FBDIV_SHIFT 0
66 #define PLL_FBDIV_MASK 0xfff << PLL_FBDIV_SHIFT
67 #define PLL_POSTDIV2_SHIFT 6
68 #define PLL_POSTDIV2_MASK 0x7 << PLL_POSTDIV2_SHIFT
69 #define PLL_REFDIV_SHIFT 0
70 #define PLL_REFDIV_MASK 0x3f << PLL_REFDIV_SHIFT
71 #define PLL_DSMPD_SHIFT 12
72 #define PLL_DSMPD_MASK 1 << PLL_DSMPD_SHIFT
73 #define PLL_FRAC_SHIFT 0
74 #define PLL_FRAC_MASK 0xffffff << PLL_FRAC_SHIFT
75 #endif
76
77 #define MIN_FOUTVCO_FREQ (800 * MHZ)
78 #define MAX_FOUTVCO_FREQ (2000 * MHZ)
79 #define MIN_FOUT_FREQ (24 * MHZ)
80 #define MAX_FOUT_FREQ (1400 * MHZ)
81
82 #define EXPONENT_OF_FRAC_PLL 24
83 #define RK_PLL_MODE_SLOW 0
84 #define RK_PLL_MODE_NORMAL 1
85 #define RK_PLL_MODE_DEEP 2
86 #define PLL_GET_PLLMODE(val, shift, mask) (((uint32_t)(val) & mask) >> shift)
87
88 #define PLL_GET_FBDIV(x) (((uint32_t)(x) & (PLL_FBDIV_MASK)) >> PLL_FBDIV_SHIFT)
89 #define PLL_GET_REFDIV(x) \
90 (((uint32_t)(x) & (PLL_REFDIV_MASK)) >> PLL_REFDIV_SHIFT)
91 #define PLL_GET_POSTDIV1(x) \
92 (((uint32_t)(x) & (PLL_POSTDIV1_MASK)) >> PLL_POSTDIV1_SHIFT)
93 #define PLL_GET_POSTDIV2(x) \
94 (((uint32_t)(x) & (PLL_POSTDIV2_MASK)) >> PLL_POSTDIV2_SHIFT)
95 #define PLL_GET_DSMPD(x) (((uint32_t)(x) & (PLL_DSMPD_MASK)) >> PLL_DSMPD_SHIFT)
96 #define PLL_GET_FRAC(x) (((uint32_t)(x) & (PLL_FRAC_MASK)) >> PLL_FRAC_SHIFT)
97
98 #define CRU_PLL_ROUND_UP_TO_KHZ(x) (HAL_DIV_ROUND_UP((x), KHZ) * KHZ)
99
100 /********************* Private Structure Definition **************************/
101 static struct PLL_CONFIG g_rockchipAutoTable;
102
103 /********************* Private Variable Definition ***************************/
104
105 /********************* Private Function Definition ***************************/
106
107 /** Calculate the greatest common divisor */
CRU_Gcd(uint32_t m,uint32_t n)108 static uint32_t CRU_Gcd(uint32_t m, uint32_t n)
109 {
110 int t;
111
112 while (m > 0) {
113 if (n > m) {
114 t = m;
115 m = n;
116 n = t;
117 }
118 m -= n;
119 }
120
121 return n;
122 }
123
124 /**
125 * @brief Rockchip pll clk set postdiv.
126 * @param foutHz: output freq
127 * @param *postDiv1: pll postDiv1
128 * @param *postDiv2: pll postDiv2
129 * @param *foutVco: pll vco
130 * @return HAL_Status.
131 * How to calculate the PLL:
132 * Formulas also embedded within the fractional PLL Verilog model:
133 * If DSMPD = 1 (DSM is disabled, "integer mode")
134 * FOUTVCO = FREF / REFDIV * FBDIV
135 * FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2
136 * Where:
137 * FOUTVCO = fractional PLL non-divided output frequency
138 * FOUTPOSTDIV = fractional PLL divided output frequency
139 * (output of second post divider)
140 */
CRU_PllSetPostDiv(uint32_t foutHz,uint32_t * postDiv1,uint32_t * postDiv2,uint32_t * foutVco)141 static HAL_Status CRU_PllSetPostDiv(uint32_t foutHz, uint32_t *postDiv1,
142 uint32_t *postDiv2, uint32_t *foutVco)
143 {
144 uint32_t freq;
145
146 if (foutHz < MIN_FOUTVCO_FREQ) {
147 for (*postDiv1 = 1; *postDiv1 <= 7; (*postDiv1)++) {
148 for (*postDiv2 = 1; *postDiv2 <= 7; (*postDiv2)++) {
149 freq = foutHz * (*postDiv1) * (*postDiv2);
150 if (freq >= MIN_FOUTVCO_FREQ && freq <= MAX_FOUTVCO_FREQ) {
151 *foutVco = freq;
152
153 return HAL_OK;
154 }
155 }
156 }
157
158 return HAL_ERROR;
159 } else {
160 *postDiv1 = 1;
161 *postDiv2 = 1;
162
163 return HAL_OK;
164 }
165 }
166
167 /**
168 * @brief Get pll parameter by auto.
169 * @param finHz: pll intput freq
170 * @param foutHz: pll output freq
171 * @return struct PLL_CONFIG.
172 * How to calculate the PLL:
173 * Formulas also embedded within the fractional PLL Verilog model:
174 * If DSMPD = 1 (DSM is disabled, "integer mode")
175 * FOUTVCO = FREF / REFDIV * FBDIV
176 * FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2
177 * Where:
178 * FOUTVCO = fractional PLL non-divided output frequency
179 * FOUTPOSTDIV = fractional PLL divided output frequency
180 * (output of second post divider)
181 * FREF = fractional PLL input reference frequency, (the OSC_HZ 24MHz input)
182 * REFDIV = fractional PLL input reference clock divider
183 * FBDIV = Integer value programmed into feedback divide
184 */
CRU_PllSetByAuto(uint32_t finHz,uint32_t foutHz)185 static const struct PLL_CONFIG *CRU_PllSetByAuto(uint32_t finHz,
186 uint32_t foutHz)
187 {
188 struct PLL_CONFIG *rateTable = &g_rockchipAutoTable;
189 uint32_t foutVco = foutHz;
190 uint64_t fin64, frac64;
191 uint32_t postDiv1, postDiv2;
192 uint32_t clkGcd = 0;
193 HAL_Status error;
194
195 if (finHz == 0 || foutHz == 0 || foutHz == finHz) {
196 return NULL;
197 }
198
199 error = CRU_PllSetPostDiv(foutHz, &postDiv1, &postDiv2, &foutVco);
200 if (error) {
201 return NULL;
202 }
203 rateTable->postDiv1 = postDiv1;
204 rateTable->postDiv2 = postDiv2;
205 rateTable->dsmpd = 1;
206
207 if (finHz / MHZ * MHZ == finHz && foutHz / MHZ * MHZ == foutHz) {
208 finHz /= MHZ;
209 foutVco /= MHZ;
210 clkGcd = CRU_Gcd(finHz, foutVco);
211 rateTable->refDiv = finHz / clkGcd;
212 rateTable->fbDiv = foutVco / clkGcd;
213
214 rateTable->frac = 0;
215 } else if (finHz / MHZ * MHZ != finHz) {
216 clkGcd = foutHz / finHz;
217 rateTable->fbDiv = clkGcd;
218 rateTable->refDiv = 1;
219 rateTable->postDiv1 = 1;
220 rateTable->postDiv2 = 1;
221
222 fin64 = foutHz * rateTable->refDiv;
223 fin64 = HAL_DivU64(fin64 << EXPONENT_OF_FRAC_PLL, finHz);
224 frac64 = rateTable->fbDiv;
225 frac64 = rateTable->fbDiv << EXPONENT_OF_FRAC_PLL;
226 frac64 = fin64 - frac64;
227 rateTable->frac = frac64;
228 if (rateTable->frac > 0) {
229 rateTable->dsmpd = 0;
230 }
231 } else {
232 clkGcd = CRU_Gcd(finHz / MHZ, foutVco / MHZ);
233 rateTable->refDiv = finHz / MHZ / clkGcd;
234 rateTable->fbDiv = foutVco / MHZ / clkGcd;
235 rateTable->frac = 0;
236
237 frac64 = (foutVco % MHZ);
238 fin64 = finHz;
239 frac64 = frac64 * rateTable->refDiv;
240 frac64 = HAL_DivU64(frac64 << EXPONENT_OF_FRAC_PLL, fin64);
241 rateTable->frac = frac64;
242 if (rateTable->frac > 0) {
243 rateTable->dsmpd = 0;
244 }
245 }
246
247 return rateTable;
248 }
249
250 /**
251 * @brief Get pll parameter by rateTable.
252 * @param *pSetup: struct PLL_SETUP struct, Contains PLL register parameters
253 * @param rate: pll target rate.
254 * @return struct PLL_CONFIG.
255 * How to calculate the PLL:
256 * Look up the rateTable to get the PLL config parameter
257 */
CRU_PllGetSettings(struct PLL_SETUP * pSetup,uint32_t rate)258 static const struct PLL_CONFIG *CRU_PllGetSettings(struct PLL_SETUP *pSetup,
259 uint32_t rate)
260 {
261 const struct PLL_CONFIG *rateTable = pSetup->rateTable;
262
263 if (rateTable == NULL) {
264 return CRU_PllSetByAuto(PLL_INPUT_OSC_RATE, rate);
265 }
266
267 while (rateTable->rate) {
268 if (rateTable->rate == rate) {
269 break;
270 }
271 rateTable++;
272 }
273 if (rateTable->rate != rate) {
274 return CRU_PllSetByAuto(PLL_INPUT_OSC_RATE, rate);
275 } else {
276 return rateTable;
277 }
278 }
279 /** @} */
280 /********************* Public Function Definition ****************************/
281
282 /** @defgroup CRU_Exported_Functions_Group5 Other Functions
283 * @attention these APIs allow direct use in the HAL layer.
284 * @{
285 */
286
287 #if defined(SOC_RV1108)
288 /**
289 * @brief Get pll freq.
290 * @param *pSetup: struct PLL_SETUP struct,Contains PLL register parameters
291 * @return pll rate.
292 * How to calculate the PLL:
293 * Formulas also embedded within the fractional PLL Verilog model:
294 * If DSMPD = 1 (DSM is disabled, "integer mode")
295 * FOUTVCO = FREF / REFDIV * FBDIV
296 * FOUT = FOUTVCO / POSTDIV1 / POSTDIV2
297 * If DSMPD = 0 (DSM is enabled, "fractional mode")
298 * FOUTVCO = (FREF / REFDIV) * (FBDIV + FRAC / (2^24))
299 * FOUTPOSTDIV = FOUTVCO / (POSTDIV1*POSTDIV2)
300 * FOUT = FOUTVCO / POSTDIV1 / POSTDIV2
301 */
HAL_CRU_GetPllFreq(struct PLL_SETUP * pSetup)302 uint32_t HAL_CRU_GetPllFreq(struct PLL_SETUP *pSetup)
303 {
304 uint32_t refDiv, fbDiv, postdDv1, postDiv2, frac, dsmpd;
305 uint32_t mode = 0, rate = PLL_INPUT_OSC_RATE;
306
307 mode = PLL_GET_PLLMODE(READ_REG(*(pSetup->modeOffset)), pSetup->modeShift,
308 pSetup->modeMask);
309
310 switch (mode) {
311 case RK_PLL_MODE_SLOW:
312 rate = PLL_INPUT_OSC_RATE;
313 break;
314 case RK_PLL_MODE_NORMAL:
315 fbDiv = PLL_GET_FBDIV(READ_REG(*(pSetup->conOffset0)));
316 postdDv1 = PLL_GET_POSTDIV1(READ_REG(*(pSetup->conOffset1)));
317 postDiv2 = PLL_GET_POSTDIV2(READ_REG(*(pSetup->conOffset1)));
318 refDiv = PLL_GET_REFDIV(READ_REG(*(pSetup->conOffset1)));
319 dsmpd = PLL_GET_DSMPD(READ_REG(*(pSetup->conOffset3)));
320 frac = PLL_GET_FRAC(READ_REG(*(pSetup->conOffset2)));
321 rate = (rate / refDiv) * fbDiv;
322 if (dsmpd == 0) {
323 uint64_t fracRate = PLL_INPUT_OSC_RATE;
324
325 fracRate *= frac;
326 fracRate = fracRate >> EXPONENT_OF_FRAC_PLL;
327 fracRate = fracRate / refDiv;
328 rate += fracRate;
329 }
330 rate = rate / (postdDv1 * postDiv2);
331 rate = CRU_PLL_ROUND_UP_TO_KHZ(rate);
332 break;
333 case RK_PLL_MODE_DEEP:
334 default:
335 rate = 32768;
336 break;
337 }
338
339 return rate;
340 }
341
342 /**
343 * @brief Set pll freq.
344 * @param *pSetup: struct PLL_SETUP struct,Contains PLL register parameters
345 * @param rate: pll set rate
346 * @return HAL_Status.
347 * How to calculate the PLL:
348 * Force PLL into slow mode
349 * Pll Power down
350 * Pll Config fbDiv, refDiv, postdDv1, postDiv2, dsmpd, frac
351 * Pll Power up
352 * Waiting for pll lock
353 * Force PLL into normal mode
354 */
HAL_CRU_SetPllFreq(struct PLL_SETUP * pSetup,uint32_t rate)355 HAL_Status HAL_CRU_SetPllFreq(struct PLL_SETUP *pSetup, uint32_t rate)
356 {
357 const struct PLL_CONFIG *pConfig;
358 int delay = 2400;
359
360 if (rate == HAL_CRU_GetPllFreq(pSetup)) {
361 return HAL_OK;
362 } else if (rate < MIN_FOUT_FREQ) {
363 return HAL_INVAL;
364 } else if (rate > MAX_FOUT_FREQ) {
365 return HAL_INVAL;
366 }
367
368 pConfig = CRU_PllGetSettings(pSetup, rate);
369 if (!pConfig) {
370 return HAL_ERROR;
371 }
372
373 /* Force PLL into slow mode to ensure output stable clock */
374 WRITE_REG_MASK_WE(*(pSetup->modeOffset), pSetup->modeMask, RK_PLL_MODE_SLOW << pSetup->modeShift);
375
376 /* Pll Power down */
377 WRITE_REG_MASK_WE(*(pSetup->conOffset3), PWRDOWN_MASK, 1 << PWRDOWN_SHIT);
378
379 /* Pll Config */
380 WRITE_REG_MASK_WE(*(pSetup->conOffset1), PLL_POSTDIV2_MASK, pConfig->postDiv2 << PLL_POSTDIV2_SHIFT);
381 WRITE_REG_MASK_WE(*(pSetup->conOffset1), PLL_REFDIV_MASK, pConfig->refDiv << PLL_REFDIV_SHIFT);
382 WRITE_REG_MASK_WE(*(pSetup->conOffset1), PLL_POSTDIV1_MASK, pConfig->postDiv1 << PLL_POSTDIV1_SHIFT);
383 WRITE_REG_MASK_WE(*(pSetup->conOffset0), PLL_FBDIV_MASK, pConfig->fbDiv << PLL_FBDIV_SHIFT);
384 WRITE_REG_MASK_WE(*(pSetup->conOffset3), PLL_DSMPD_MASK, pConfig->dsmpd << PLL_DSMPD_SHIFT);
385
386 if (pConfig->frac) {
387 WRITE_REG(*(pSetup->conOffset2), (READ_REG(*(pSetup->conOffset2)) & 0xff000000) | pConfig->frac);
388 }
389
390 WRITE_REG_MASK_WE(*(pSetup->conOffset3), PWRDOWN_MASK, 0 << PWRDOWN_SHIT);
391
392 /* Waiting for pll lock */
393 while (delay > 0) {
394 if (READ_REG(*(pSetup->conOffset2)) & (1 << pSetup->lockShift)) {
395 break;
396 }
397 HAL_CPUDelayUs(1000);
398 delay--;
399 }
400 if (delay == 0) {
401 return HAL_TIMEOUT;
402 }
403
404 /* Force PLL into normal mode */
405 WRITE_REG_MASK_WE(*(pSetup->modeOffset), pSetup->modeMask, RK_PLL_MODE_NORMAL << pSetup->modeShift);
406
407 return HAL_OK;
408 }
409
410 /**
411 * @brief Set pll power up.
412 * @param *pSetup: struct PLL_SETUP struct,Contains PLL register parameters
413 * @return HAL_Status.
414 */
HAL_CRU_SetPllPowerUp(struct PLL_SETUP * pSetup)415 HAL_Status HAL_CRU_SetPllPowerUp(struct PLL_SETUP *pSetup)
416 {
417 int delay = 2400;
418
419 /* Pll Power up */
420 WRITE_REG_MASK_WE(*(pSetup->conOffset3), PWRDOWN_MASK, 0 << PWRDOWN_SHIT);
421
422 /* Waiting for pll lock */
423 while (delay > 0) {
424 if (READ_REG(*(pSetup->conOffset2)) & (1 << pSetup->lockShift)) {
425 break;
426 }
427 HAL_CPUDelayUs(1000);
428 delay--;
429 }
430 if (delay == 0) {
431 return HAL_TIMEOUT;
432 }
433
434 return HAL_OK;
435 }
436
437 /**
438 * @brief Set pll power down.
439 * @param *pSetup: struct PLL_SETUP struct,Contains PLL register parameters
440 * @return HAL_Status.
441 */
HAL_CRU_SetPllPowerDown(struct PLL_SETUP * pSetup)442 HAL_Status HAL_CRU_SetPllPowerDown(struct PLL_SETUP *pSetup)
443 {
444 /* Pll Power down */
445 WRITE_REG_MASK_WE(*(pSetup->conOffset3), PWRDOWN_MASK, 1 << PWRDOWN_SHIT);
446
447 return HAL_OK;
448 }
449 #else
450 /**
451 * @brief Get pll freq.
452 * @param *pSetup: struct PLL_SETUP struct,Contains PLL register parameters
453 * @return pll rate.
454 * How to calculate the PLL:
455 * Formulas also embedded within the fractional PLL Verilog model:
456 * If DSMPD = 1 (DSM is disabled, "integer mode")
457 * FOUTVCO = FREF / REFDIV * FBDIV
458 * FOUT = FOUTVCO / POSTDIV1 / POSTDIV2
459 * If DSMPD = 0 (DSM is enabled, "fractional mode")
460 * FOUTVCO = (FREF / REFDIV) * (FBDIV + FRAC / (2^24))
461 * FOUTPOSTDIV = FOUTVCO / (POSTDIV1*POSTDIV2)
462 * FOUT = FOUTVCO / POSTDIV1 / POSTDIV2
463 */
HAL_CRU_GetPllFreq(struct PLL_SETUP * pSetup)464 uint32_t HAL_CRU_GetPllFreq(struct PLL_SETUP *pSetup)
465 {
466 uint32_t refDiv, fbDiv, postdDv1, postDiv2, frac, dsmpd;
467 uint32_t mode = 0, rate = PLL_INPUT_OSC_RATE;
468
469 mode = PLL_GET_PLLMODE(READ_REG(*(pSetup->modeOffset)), pSetup->modeShift,
470 pSetup->modeMask);
471
472 switch (mode) {
473 case RK_PLL_MODE_SLOW:
474 rate = PLL_INPUT_OSC_RATE;
475 break;
476 case RK_PLL_MODE_NORMAL:
477 postdDv1 = PLL_GET_POSTDIV1(READ_REG(*(pSetup->conOffset0)));
478 fbDiv = PLL_GET_FBDIV(READ_REG(*(pSetup->conOffset0)));
479 postDiv2 = PLL_GET_POSTDIV2(READ_REG(*(pSetup->conOffset1)));
480 refDiv = PLL_GET_REFDIV(READ_REG(*(pSetup->conOffset1)));
481 dsmpd = PLL_GET_DSMPD(READ_REG(*(pSetup->conOffset1)));
482 frac = PLL_GET_FRAC(READ_REG(*(pSetup->conOffset2)));
483 rate = (rate / refDiv) * fbDiv;
484 if (dsmpd == 0) {
485 uint64_t fracRate = PLL_INPUT_OSC_RATE;
486
487 fracRate *= frac;
488 fracRate = fracRate >> EXPONENT_OF_FRAC_PLL;
489 fracRate = fracRate / refDiv;
490 rate += fracRate;
491 }
492 rate = rate / (postdDv1 * postDiv2);
493 rate = CRU_PLL_ROUND_UP_TO_KHZ(rate);
494 break;
495 case RK_PLL_MODE_DEEP:
496 default:
497 rate = 32768;
498 break;
499 }
500
501 return rate;
502 }
503
504 /**
505 * @brief Set pll freq.
506 * @param *pSetup: struct PLL_SETUP struct,Contains PLL register parameters
507 * @param rate: pll set rate
508 * @return HAL_Status.
509 * How to calculate the PLL:
510 * Force PLL into slow mode
511 * Pll Power down
512 * Pll Config fbDiv, refDiv, postdDv1, postDiv2, dsmpd, frac
513 * Pll Power up
514 * Waiting for pll lock
515 * Force PLL into normal mode
516 */
HAL_CRU_SetPllFreq(struct PLL_SETUP * pSetup,uint32_t rate)517 HAL_Status HAL_CRU_SetPllFreq(struct PLL_SETUP *pSetup, uint32_t rate)
518 {
519 const struct PLL_CONFIG *pConfig;
520 int delay = 2400;
521
522 if (rate == HAL_CRU_GetPllFreq(pSetup)) {
523 return HAL_OK;
524 } else if (rate < MIN_FOUT_FREQ) {
525 return HAL_INVAL;
526 } else if (rate > MAX_FOUT_FREQ) {
527 return HAL_INVAL;
528 }
529
530 pConfig = CRU_PllGetSettings(pSetup, rate);
531 if (!pConfig) {
532 return HAL_ERROR;
533 }
534
535 /* Force PLL into slow mode to ensure output stable clock */
536 WRITE_REG_MASK_WE(*(pSetup->modeOffset), pSetup->modeMask, RK_PLL_MODE_SLOW << pSetup->modeShift);
537
538 /* Pll Power down */
539 WRITE_REG_MASK_WE(*(pSetup->conOffset1), PWRDOWN_MASK, 1 << PWRDOWN_SHIT);
540
541 /* Pll Config */
542 WRITE_REG_MASK_WE(*(pSetup->conOffset1), PLL_POSTDIV2_MASK, pConfig->postDiv2 << PLL_POSTDIV2_SHIFT);
543 WRITE_REG_MASK_WE(*(pSetup->conOffset1), PLL_REFDIV_MASK, pConfig->refDiv << PLL_REFDIV_SHIFT);
544 WRITE_REG_MASK_WE(*(pSetup->conOffset0), PLL_POSTDIV1_MASK, pConfig->postDiv1 << PLL_POSTDIV1_SHIFT);
545 WRITE_REG_MASK_WE(*(pSetup->conOffset0), PLL_FBDIV_MASK, pConfig->fbDiv << PLL_FBDIV_SHIFT);
546 WRITE_REG_MASK_WE(*(pSetup->conOffset1), PLL_DSMPD_MASK, pConfig->dsmpd << PLL_DSMPD_SHIFT);
547
548 if (pConfig->frac) {
549 WRITE_REG(*(pSetup->conOffset2), (READ_REG(*(pSetup->conOffset2)) & 0xff000000) | pConfig->frac);
550 }
551
552 /* Pll Power up */
553 WRITE_REG_MASK_WE(*(pSetup->conOffset1), PWRDOWN_MASK, 0 << PWRDOWN_SHIT);
554
555 /* Waiting for pll lock */
556 while (delay > 0) {
557 if (pSetup->stat0) {
558 if (READ_REG(*(pSetup->stat0)) & (1 << pSetup->lockShift)) {
559 break;
560 }
561 } else {
562 if (READ_REG(*(pSetup->conOffset1)) & (1 << pSetup->lockShift)) {
563 break;
564 }
565 }
566 HAL_CPUDelayUs(1000);
567 delay--;
568 }
569 if (delay == 0) {
570 return HAL_TIMEOUT;
571 }
572
573 /* Force PLL into normal mode */
574 WRITE_REG_MASK_WE(*(pSetup->modeOffset), pSetup->modeMask, RK_PLL_MODE_NORMAL << pSetup->modeShift);
575
576 return HAL_OK;
577 }
578
579 /**
580 * @brief Set pll power up.
581 * @param *pSetup: struct PLL_SETUP struct,Contains PLL register parameters
582 * @return HAL_Status.
583 */
HAL_CRU_SetPllPowerUp(struct PLL_SETUP * pSetup)584 HAL_Status HAL_CRU_SetPllPowerUp(struct PLL_SETUP *pSetup)
585 {
586 int delay = 2400;
587
588 /* Pll Power up */
589 WRITE_REG_MASK_WE(*(pSetup->conOffset1), PWRDOWN_MASK, 0 << PWRDOWN_SHIT);
590
591 /* Waiting for pll lock */
592 while (delay > 0) {
593 if (pSetup->stat0) {
594 if (READ_REG(*(pSetup->stat0)) & (1 << pSetup->lockShift)) {
595 break;
596 }
597 } else {
598 if (READ_REG(*(pSetup->conOffset1)) & (1 << pSetup->lockShift)) {
599 break;
600 }
601 }
602 HAL_CPUDelayUs(1000);
603 delay--;
604 }
605 if (delay == 0) {
606 return HAL_TIMEOUT;
607 }
608
609 return HAL_OK;
610 }
611
612 /**
613 * @brief Set pll power down.
614 * @param *pSetup: struct PLL_SETUP struct,Contains PLL register parameters
615 * @return HAL_Status.
616 */
HAL_CRU_SetPllPowerDown(struct PLL_SETUP * pSetup)617 HAL_Status HAL_CRU_SetPllPowerDown(struct PLL_SETUP *pSetup)
618 {
619 /* Pll Power down */
620 WRITE_REG_MASK_WE(*(pSetup->conOffset1), PWRDOWN_MASK, 1 << PWRDOWN_SHIT);
621
622 return HAL_OK;
623 }
624 #endif
625
626 /**
627 * @brief IP Clock is Enabled API
628 * @param clk: clk gate id
629 * @return HAL_Check
630 */
HAL_CRU_ClkIsEnabled(uint32_t clk)631 HAL_Check HAL_CRU_ClkIsEnabled(uint32_t clk)
632 {
633 uint32_t index = CLK_GATE_GET_REG_OFFSET(clk);
634 uint32_t shift = CLK_GATE_GET_BITS_SHIFT(clk);
635 HAL_Check ret;
636
637 #ifdef CRU_GATE_CON_CNT
638 if (index < CRU_GATE_CON_CNT) {
639 ret = (HAL_Check)(!((CRU->CRU_CLKGATE_CON[index] & (1 << shift)) >> shift));
640 } else {
641 #ifdef PMUCRU_BASE
642 ret = (HAL_Check)(!((PMUCRU->CRU_CLKGATE_CON[index - CRU_GATE_CON_CNT] & (1 << shift)) >> shift));
643 #else
644 ret = (HAL_Check)(!((CRU->PMU_CLKGATE_CON[index - CRU_GATE_CON_CNT] & (1 << shift)) >> shift));
645 #endif
646 }
647 #else
648 ret = (HAL_Check)(!((CRU->CRU_CLKGATE_CON[index] & (1 << shift)) >> shift));
649 #endif
650
651 return ret;
652 }
653
654 /**
655 * @brief IP Clock Enable API
656 * @param clk: clk gate id
657 * @return NONE
658 */
HAL_CRU_ClkEnable(uint32_t clk)659 HAL_Status HAL_CRU_ClkEnable(uint32_t clk)
660 {
661 uint32_t index = CLK_GATE_GET_REG_OFFSET(clk);
662 uint32_t shift = CLK_GATE_GET_BITS_SHIFT(clk);
663
664 #ifdef CRU_GATE_CON_CNT
665 if (index < CRU_GATE_CON_CNT) {
666 CRU->CRU_CLKGATE_CON[index] = VAL_MASK_WE(1U << shift, 0U << shift);
667 } else {
668 #ifdef PMUCRU_BASE
669 PMUCRU->CRU_CLKGATE_CON[index - CRU_GATE_CON_CNT] = VAL_MASK_WE(1U << shift, 0U << shift);
670 #else
671 CRU->PMU_CLKGATE_CON[index - CRU_GATE_CON_CNT] = VAL_MASK_WE(1U << shift, 0U << shift);
672 #endif
673 }
674 #else
675 CRU->CRU_CLKGATE_CON[index] = VAL_MASK_WE(1U << shift, 0U << shift);
676 #endif
677
678 return HAL_OK;
679 }
680
681 /**
682 * @brief IP Clock Disabled API
683 * @param clk: clk gate id
684 * @return NONE
685 */
HAL_CRU_ClkDisable(uint32_t clk)686 HAL_Status HAL_CRU_ClkDisable(uint32_t clk)
687 {
688 uint32_t index = CLK_GATE_GET_REG_OFFSET(clk);
689 uint32_t shift = CLK_GATE_GET_BITS_SHIFT(clk);
690
691 #ifdef CRU_GATE_CON_CNT
692 if (index < CRU_GATE_CON_CNT) {
693 CRU->CRU_CLKGATE_CON[index] = VAL_MASK_WE(1U << shift, 1U << shift);
694 } else {
695 #ifdef PMUCRU_BASE
696 PMUCRU->CRU_CLKGATE_CON[index - CRU_GATE_CON_CNT] = VAL_MASK_WE(1U << shift, 1U << shift);
697 #else
698 CRU->PMU_CLKGATE_CON[index - CRU_GATE_CON_CNT] = VAL_MASK_WE(1U << shift, 1U << shift);
699 #endif
700 }
701 #else
702 CRU->CRU_CLKGATE_CON[index] = VAL_MASK_WE(1U << shift, 1U << shift);
703 #endif
704
705 return HAL_OK;
706 }
707
708 /**
709 * @brief IP Clock is reset API
710 * @param clk: clk reset id
711 * @return HAL_Check
712 */
HAL_CRU_ClkIsReset(uint32_t clk)713 HAL_Check HAL_CRU_ClkIsReset(uint32_t clk)
714 {
715 uint32_t index = CLK_GATE_GET_REG_OFFSET(clk);
716 uint32_t shift = CLK_GATE_GET_BITS_SHIFT(clk);
717 HAL_Check ret;
718
719 #ifdef CRU_SRST_CON_CNT
720 if (index < CRU_SRST_CON_CNT) {
721 ret = (HAL_Check)((CRU->CRU_CLKGATE_CON[index] & (1 << shift)) >> shift);
722 } else {
723 ret = (HAL_Check)((PMUCRU->CRU_CLKGATE_CON[index - CRU_SRST_CON_CNT] & (1 << shift)) >> shift);
724 }
725 #else
726 ret = (HAL_Check)((CRU->CRU_CLKGATE_CON[index] & (1 << shift)) >> shift);
727 #endif
728
729 return ret;
730 }
731
732 /**
733 * @brief IP Clock Reset Assert API
734 * @param clk: clk reset id
735 * @return NONE
736 */
HAL_CRU_ClkResetAssert(uint32_t clk)737 HAL_Status HAL_CRU_ClkResetAssert(uint32_t clk)
738 {
739 uint32_t index = CLK_RESET_GET_REG_OFFSET(clk);
740 uint32_t shift = CLK_RESET_GET_BITS_SHIFT(clk);
741
742 HAL_ASSERT(shift < 16);
743 #ifdef CRU_SRST_CON_CNT
744 if (index < CRU_SRST_CON_CNT) {
745 CRU->CRU_SOFTRST_CON[index] = VAL_MASK_WE(1U << shift, 1U << shift);
746 } else {
747 PMUCRU->CRU_SOFTRST_CON[index - CRU_SRST_CON_CNT] = VAL_MASK_WE(1U << shift, 1U << shift);
748 }
749 #else
750 CRU->CRU_SOFTRST_CON[index] = VAL_MASK_WE(1U << shift, 1U << shift);
751 #endif
752
753 return HAL_OK;
754 }
755
756 /**
757 * @brief IP Clock Reset Deassert API
758 * @param clk: clk reset id
759 * @return NONE
760 */
HAL_CRU_ClkResetDeassert(uint32_t clk)761 HAL_Status HAL_CRU_ClkResetDeassert(uint32_t clk)
762 {
763 uint32_t index = CLK_RESET_GET_REG_OFFSET(clk);
764 uint32_t shift = CLK_RESET_GET_BITS_SHIFT(clk);
765
766 HAL_ASSERT(shift < 16);
767 #ifdef CRU_SRST_CON_CNT
768 if (index < CRU_SRST_CON_CNT) {
769 CRU->CRU_SOFTRST_CON[index] = VAL_MASK_WE(1U << shift, 0U << shift);
770 } else {
771 PMUCRU->CRU_SOFTRST_CON[index - CRU_SRST_CON_CNT] = VAL_MASK_WE(1U << shift, 0U << shift);
772 }
773 #else
774 CRU->CRU_SOFTRST_CON[index] = VAL_MASK_WE(1U << shift, 0U << shift);
775 #endif
776
777 return HAL_OK;
778 }
779
780 /**
781 * @brief IP Clock set div API
782 * @param divName: div id(Contains div offset, shift, mask information)
783 * @param divValue: div value
784 * @return NONE
785 */
HAL_CRU_ClkSetDiv(uint32_t divName,uint32_t divValue)786 HAL_Status HAL_CRU_ClkSetDiv(uint32_t divName, uint32_t divValue)
787 {
788 uint32_t shift, mask, index;
789
790 index = CLK_DIV_GET_REG_OFFSET(divName);
791 shift = CLK_DIV_GET_BITS_SHIFT(divName);
792 HAL_ASSERT(shift < 16);
793 mask = CLK_DIV_GET_MASK(divName);
794 if (divValue > mask) {
795 divValue = mask;
796 }
797
798 #ifdef CRU_CLK_DIV_CON_CNT
799 if (index < CRU_CLK_DIV_CON_CNT) {
800 CRU->CRU_CLKSEL_CON[index] = VAL_MASK_WE(mask, (divValue - 1U) << shift);
801 } else {
802 #ifdef PMUCRU_BASE
803 PMUCRU->CRU_CLKSEL_CON[index - CRU_CLK_DIV_CON_CNT] = VAL_MASK_WE(mask, (divValue - 1U) << shift);
804 #else
805 CRU->PMU_CLKSEL_CON[index - CRU_CLK_DIV_CON_CNT] = VAL_MASK_WE(mask, (divValue - 1U) << shift);
806 #endif
807 }
808 #else
809 CRU->CRU_CLKSEL_CON[index] = VAL_MASK_WE(mask, (divValue - 1U) << shift);
810 #endif
811
812 return HAL_OK;
813 }
814
815 /**
816 * @brief IP Clock get div API
817 * @param divName: div id(Contains div offset, shift, mask information)
818 * @return div value
819 */
HAL_CRU_ClkGetDiv(uint32_t divName)820 uint32_t HAL_CRU_ClkGetDiv(uint32_t divName)
821 {
822 uint32_t shift, mask, index, divValue;
823
824 index = CLK_DIV_GET_REG_OFFSET(divName);
825 shift = CLK_DIV_GET_BITS_SHIFT(divName);
826 HAL_ASSERT(shift < 16);
827 mask = CLK_DIV_GET_MASK(divName);
828
829 #ifdef CRU_CLK_DIV_CON_CNT
830 if (index < CRU_CLK_DIV_CON_CNT) {
831 divValue = ((((CRU->CRU_CLKSEL_CON[index]) & mask) >> shift) + 1);
832 } else {
833 #ifdef PMUCRU_BASE
834 divValue = ((((PMUCRU->CRU_CLKSEL_CON[index - CRU_CLK_DIV_CON_CNT]) & mask) >> shift) + 1);
835 #else
836 divValue = ((((CRU->PMU_CLKSEL_CON[index - CRU_CLK_DIV_CON_CNT]) & mask) >> shift) + 1);
837 #endif
838 }
839 #else
840 divValue = ((((CRU->CRU_CLKSEL_CON[index]) & mask) >> shift) + 1);
841 #endif
842
843 return divValue;
844 }
845
846 /**
847 * @brief IP Clock set mux API
848 * @param muxName: mux id(Contains mux offset, shift, mask information)
849 * @param muxValue: mux value
850 * @return NONE
851 */
852 HAL_SECTION_SRAM_CODE
HAL_CRU_ClkSetMux(uint32_t muxName,uint32_t muxValue)853 HAL_Status HAL_CRU_ClkSetMux(uint32_t muxName, uint32_t muxValue)
854 {
855 uint32_t shift, mask, index;
856
857 index = CLK_MUX_GET_REG_OFFSET(muxName);
858 shift = CLK_MUX_GET_BITS_SHIFT(muxName);
859 HAL_ASSERT(shift < 16);
860 mask = CLK_MUX_GET_MASK(muxName);
861
862 #ifdef CRU_CLK_SEL_CON_CNT
863 if (index < CRU_CLK_DIV_CON_CNT) {
864 CRU->CRU_CLKSEL_CON[index] = VAL_MASK_WE(mask, muxValue << shift);
865 } else {
866 #ifdef PMUCRU_BASE
867 PMUCRU->CRU_CLKSEL_CON[index - CRU_CLK_SEL_CON_CNT] = VAL_MASK_WE(mask, muxValue << shift);
868 #else
869 CRU->PMU_CLKSEL_CON[index - CRU_CLK_SEL_CON_CNT] = VAL_MASK_WE(mask, muxValue << shift);
870 #endif
871 }
872 #else
873 CRU->CRU_CLKSEL_CON[index] = VAL_MASK_WE(mask, muxValue << shift);
874 #endif
875
876 return HAL_OK;
877 }
878
879 /**
880 * @brief IP Clock get mux API
881 * @param muxName: mux id(Contains mux offset, shift, mask information)
882 * @return mux value
883 */
884 HAL_SECTION_SRAM_CODE
HAL_CRU_ClkGetMux(uint32_t muxName)885 uint32_t HAL_CRU_ClkGetMux(uint32_t muxName)
886 {
887 uint32_t shift, mask, index, muxValue;
888
889 index = CLK_MUX_GET_REG_OFFSET(muxName);
890 shift = CLK_MUX_GET_BITS_SHIFT(muxName);
891 HAL_ASSERT(shift < 16);
892 mask = CLK_MUX_GET_MASK(muxName);
893
894 #ifdef CRU_CLK_SEL_CON_CNT
895 if (index < CRU_CLK_SEL_CON_CNT) {
896 muxValue = ((CRU->CRU_CLKSEL_CON[index] & mask) >> shift);
897 } else {
898 #ifdef PMUCRU_BASE
899 muxValue = ((PMUCRU->CRU_CLKSEL_CON[index - CRU_CLK_SEL_CON_CNT] & mask) >> shift);
900 #else
901 muxValue = ((CRU->PMU_CLKSEL_CON[index - CRU_CLK_SEL_CON_CNT] & mask) >> shift);
902 #endif
903 }
904 #else
905 muxValue = ((CRU->CRU_CLKSEL_CON[index] & mask) >> shift);
906 #endif
907
908 return muxValue;
909 }
910
911 /**
912 * @brief Get frac div config.
913 * @param rateOut: clk out rate.
914 * @param rate: clk src rate.
915 * @param numerator: the returned numerator.
916 * @param denominator: the returned denominator.
917 * @return HAL_Status.
918 */
HAL_CRU_FracdivGetConfig(uint32_t rateOut,uint32_t rate,uint32_t * numerator,uint32_t * denominator)919 HAL_Status HAL_CRU_FracdivGetConfig(uint32_t rateOut, uint32_t rate,
920 uint32_t *numerator,
921 uint32_t *denominator)
922 {
923 uint32_t gcdVal;
924
925 gcdVal = CRU_Gcd(rate, rateOut);
926 if (!gcdVal) {
927 return HAL_ERROR;
928 }
929
930 *numerator = rateOut / gcdVal;
931 *denominator = rate / gcdVal;
932
933 if (*numerator < 4) {
934 *numerator *= 4;
935 *denominator *= 4;
936 }
937 if (*numerator > 0xffff || *denominator > 0xffff) {
938 return HAL_INVAL;
939 }
940
941 return HAL_OK;
942 }
943
944 /**
945 * @brief Get Np5 best div.
946 * @param clockName: clk id.
947 * @param rate: clk rate.
948 * @param pRate: clk parent rate
949 * @param bestdiv: the returned bestdiv.
950 * @return HAL_Status.
951 */
HAL_CRU_ClkNp5BestDiv(eCLOCK_Name clockName,uint32_t rate,uint32_t pRate,uint32_t * bestdiv)952 HAL_Status HAL_CRU_ClkNp5BestDiv(eCLOCK_Name clockName, uint32_t rate, uint32_t pRate, uint32_t *bestdiv)
953 {
954 uint32_t div = CLK_GET_DIV(clockName);
955 uint32_t maxDiv = CLK_DIV_GET_MASK(div);
956 uint32_t i;
957
958 for (i = 0; i < maxDiv; i++) {
959 if (((pRate * 2) == (rate * (i * 2 + 3)))) {
960 *bestdiv = i;
961
962 return HAL_OK;
963 }
964 }
965
966 return HAL_ERROR;
967 }
968
969 /**
970 * @brief vop dclk enable.
971 * @param gateId: gate id
972 * @return HAL_Status.
973 * @attention these APIs allow direct use in the HAL layer.
974 */
HAL_CRU_VopDclkEnable(uint32_t gateId)975 __WEAK HAL_Status HAL_CRU_VopDclkEnable(uint32_t gateId)
976 {
977 HAL_CRU_ClkEnable(gateId);
978
979 return HAL_OK;
980 }
981
982 /**
983 * @brief vop dclk disable.
984 * @param gateId: gate id
985 * @return HAL_Status.
986 * @attention these APIs allow direct use in the HAL layer.
987 */
HAL_CRU_VopDclkDisable(uint32_t gateId)988 __WEAK HAL_Status HAL_CRU_VopDclkDisable(uint32_t gateId)
989 {
990 HAL_CRU_ClkDisable(gateId);
991
992 return HAL_OK;
993 }
994
995 /**
996 * @brief assert CRU global software reset.
997 * @param type: global software reset type.
998 * @return HAL_INVAL if the SoC does not support.
999 */
HAL_CRU_SetGlbSrst(eCRU_GlbSrstType type)1000 HAL_Status HAL_CRU_SetGlbSrst(eCRU_GlbSrstType type)
1001 {
1002 #ifdef CRU_GLB_SRST_FST_VALUE_OFFSET
1003 if (type == GLB_SRST_FST) {
1004 CRU->GLB_SRST_FST_VALUE = GLB_SRST_FST;
1005 }
1006 #endif
1007 #ifdef CRU_GLB_SRST_SND_VALUE_OFFSET
1008 if (type == GLB_SRST_SND) {
1009 CRU->GLB_SRST_SND_VALUE = GLB_SRST_SND;
1010 }
1011 #endif
1012
1013 return HAL_INVAL;
1014 }
1015
1016 /** @} */
1017
1018 /** @} */
1019
1020 /** @} */
1021
1022 #endif /* HAL_CRU_MODULE_ENABLED */
1023