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