1 /* SPDX-License-Identifier: GPL-2.0-only */
4 #include <commonlib/bsd/gcd.h>
5 #include <console/console.h>
7 #include <device/mmio.h>
8 #include <soc/addressmap.h>
24 #define PLL_DIVISORS(hz, _refdiv, _postdiv1, _postdiv2) {\
26 .fbdiv = (u32)((u64)hz * _refdiv * _postdiv1 * _postdiv2 / OSC_HZ),\
27 .postdiv1 = _postdiv1, .postdiv2 = _postdiv2, .freq = hz};\
28 _Static_assert(((u64)hz * _refdiv * _postdiv1 * _postdiv2 / OSC_HZ) *\
29 OSC_HZ / (_refdiv * _postdiv1 * _postdiv2) == hz,\
30 STRINGIFY(hz) " Hz cannot be hit with PLL "\
31 "divisors on line " STRINGIFY(__LINE__))
33 static const struct pll_div gpll_init_cfg
= PLL_DIVISORS(GPLL_HZ
, 1, 4, 1);
34 static const struct pll_div cpll_init_cfg
= PLL_DIVISORS(CPLL_HZ
, 1, 3, 1);
35 static const struct pll_div ppll_init_cfg
= PLL_DIVISORS(PPLL_HZ
, 3, 2, 1);
37 static const struct pll_div apll_1512_cfg
= PLL_DIVISORS(1512*MHz
, 1, 1, 1);
38 static const struct pll_div apll_600_cfg
= PLL_DIVISORS(600*MHz
, 1, 3, 1);
40 static const struct pll_div
*apll_cfgs
[] = {
41 [APLL_1512_MHZ
] = &apll_1512_cfg
,
42 [APLL_600_MHZ
] = &apll_600_cfg
,
47 PLL_FBDIV_MASK
= 0xfff,
51 PLL_POSTDIV2_MASK
= 0x7,
52 PLL_POSTDIV2_SHIFT
= 12,
53 PLL_POSTDIV1_MASK
= 0x7,
54 PLL_POSTDIV1_SHIFT
= 8,
55 PLL_REFDIV_MASK
= 0x3f,
59 PLL_LOCK_STATUS_MASK
= 1,
60 PLL_LOCK_STATUS_SHIFT
= 31,
61 PLL_FRACDIV_MASK
= 0xffffff,
62 PLL_FRACDIV_SHIFT
= 0,
76 PLL_SSMOD_BP_MASK
= 1,
77 PLL_SSMOD_BP_SHIFT
= 0,
78 PLL_SSMOD_DIS_SSCG_MASK
= 1,
79 PLL_SSMOD_DIS_SSCG_SHIFT
= 1,
80 PLL_SSMOD_RESET_MASK
= 1,
81 PLL_SSMOD_RESET_SHIFT
= 2,
82 PLL_SSMOD_DOWNSPEAD_MASK
= 1,
83 PLL_SSMOD_DOWNSPEAD_SHIFT
= 3,
84 PLL_SSMOD_DIVVAL_MASK
= 0xf,
85 PLL_SSMOD_DIVVAL_SHIFT
= 4,
86 PLL_SSMOD_SPREADAMP_MASK
= 0x1f,
87 PLL_SSMOD_SPREADAMP_SHIFT
= 8,
89 /* PMUCRU_CLKSEL_CON0 */
90 PMU_PCLK_DIV_CON_MASK
= 0x1f,
91 PMU_PCLK_DIV_CON_SHIFT
= 0,
93 /* PMUCRU_CLKSEL_CON1 */
94 SPI3_PLL_SEL_MASK
= 1,
95 SPI3_PLL_SEL_SHIFT
= 7,
97 SPI3_PLL_SEL_PPLL
= 1,
98 SPI3_DIV_CON_MASK
= 0x7f,
99 SPI3_DIV_CON_SHIFT
= 0x0,
101 /* PMUCRU_CLKSEL_CON2 */
102 I2C_DIV_CON_MASK
= 0x7f,
103 I2C8_DIV_CON_SHIFT
= 8,
104 I2C0_DIV_CON_SHIFT
= 0,
106 /* PMUCRU_CLKSEL_CON3 */
107 I2C4_DIV_CON_SHIFT
= 0,
109 /* CLKSEL_CON0 / CLKSEL_CON2 */
110 ACLKM_CORE_DIV_CON_MASK
= 0x1f,
111 ACLKM_CORE_DIV_CON_SHIFT
= 8,
112 CLK_CORE_PLL_SEL_MASK
= 3,
113 CLK_CORE_PLL_SEL_SHIFT
= 6,
114 CLK_CORE_PLL_SEL_ALPLL
= 0x0,
115 CLK_CORE_PLL_SEL_ABPLL
= 0x1,
116 CLK_CORE_PLL_SEL_DPLL
= 0x10,
117 CLK_CORE_PLL_SEL_GPLL
= 0x11,
118 CLK_CORE_DIV_MASK
= 0x1f,
119 CLK_CORE_DIV_SHIFT
= 0,
121 /* CLKSEL_CON1 / CLKSEL_CON3 */
122 PCLK_DBG_DIV_MASK
= 0x1f,
123 PCLK_DBG_DIV_SHIFT
= 0x8,
124 ATCLK_CORE_DIV_MASK
= 0x1f,
125 ATCLK_CORE_DIV_SHIFT
= 0,
128 PCLK_PERIHP_DIV_CON_MASK
= 0x7,
129 PCLK_PERIHP_DIV_CON_SHIFT
= 12,
130 HCLK_PERIHP_DIV_CON_MASK
= 3,
131 HCLK_PERIHP_DIV_CON_SHIFT
= 8,
132 ACLK_PERIHP_PLL_SEL_MASK
= 1,
133 ACLK_PERIHP_PLL_SEL_SHIFT
= 7,
134 ACLK_PERIHP_PLL_SEL_CPLL
= 0,
135 ACLK_PERIHP_PLL_SEL_GPLL
= 1,
136 ACLK_PERIHP_DIV_CON_MASK
= 0x1f,
137 ACLK_PERIHP_DIV_CON_SHIFT
= 0,
140 ACLK_EMMC_PLL_SEL_MASK
= 0x1,
141 ACLK_EMMC_PLL_SEL_SHIFT
= 7,
142 ACLK_EMMC_PLL_SEL_GPLL
= 0x1,
143 ACLK_EMMC_DIV_CON_MASK
= 0x1f,
144 ACLK_EMMC_DIV_CON_SHIFT
= 0,
147 CLK_EMMC_PLL_MASK
= 0x7,
148 CLK_EMMC_PLL_SHIFT
= 8,
149 CLK_EMMC_PLL_SEL_GPLL
= 0x1,
150 CLK_EMMC_DIV_CON_MASK
= 0x7f,
151 CLK_EMMC_DIV_CON_SHIFT
= 0,
154 PCLK_PERILP0_DIV_CON_MASK
= 0x7,
155 PCLK_PERILP0_DIV_CON_SHIFT
= 12,
156 HCLK_PERILP0_DIV_CON_MASK
= 3,
157 HCLK_PERILP0_DIV_CON_SHIFT
= 8,
158 ACLK_PERILP0_PLL_SEL_MASK
= 1,
159 ACLK_PERILP0_PLL_SEL_SHIFT
= 7,
160 ACLK_PERILP0_PLL_SEL_CPLL
= 0,
161 ACLK_PERILP0_PLL_SEL_GPLL
= 1,
162 ACLK_PERILP0_DIV_CON_MASK
= 0x1f,
163 ACLK_PERILP0_DIV_CON_SHIFT
= 0,
166 PCLK_PERILP1_DIV_CON_MASK
= 0x7,
167 PCLK_PERILP1_DIV_CON_SHIFT
= 8,
168 HCLK_PERILP1_PLL_SEL_MASK
= 1,
169 HCLK_PERILP1_PLL_SEL_SHIFT
= 7,
170 HCLK_PERILP1_PLL_SEL_CPLL
= 0,
171 HCLK_PERILP1_PLL_SEL_GPLL
= 1,
172 HCLK_PERILP1_DIV_CON_MASK
= 0x1f,
173 HCLK_PERILP1_DIV_CON_SHIFT
= 0,
176 CLK_SARADC_DIV_CON_MASK
= 0xff,
177 CLK_SARADC_DIV_CON_SHIFT
= 8,
180 CLK_TSADC_SEL_X24M
= 0x0,
181 CLK_TSADC_SEL_MASK
= 1,
182 CLK_TSADC_SEL_SHIFT
= 15,
183 CLK_TSADC_DIV_CON_MASK
= 0x3ff,
184 CLK_TSADC_DIV_CON_SHIFT
= 0,
187 CLK_PCLK_EDP_PLL_SEL_MASK
= 1,
188 CLK_PCLK_EDP_PLL_SEL_SHIFT
= 15,
189 CLK_PCLK_EDP_PLL_SEL_CPLL
= 0,
190 CLK_PCLK_EDP_DIV_CON_MASK
= 0x3f,
191 CLK_PCLK_EDP_DIV_CON_SHIFT
= 8,
193 /* CLKSEL_CON47 & CLKSEL_CON48 */
194 ACLK_VOP_PLL_SEL_MASK
= 0x3,
195 ACLK_VOP_PLL_SEL_SHIFT
= 6,
196 ACLK_VOP_PLL_SEL_CPLL
= 0x1,
197 ACLK_VOP_DIV_CON_MASK
= 0x1f,
198 ACLK_VOP_DIV_CON_SHIFT
= 0,
200 /* CLKSEL_CON49 & CLKSEL_CON50 */
201 DCLK_VOP_DCLK_SEL_MASK
= 1,
202 DCLK_VOP_DCLK_SEL_SHIFT
= 11,
203 DCLK_VOP_DCLK_SEL_DIVOUT
= 0,
204 DCLK_VOP_PLL_SEL_MASK
= 3,
205 DCLK_VOP_PLL_SEL_SHIFT
= 8,
206 DCLK_VOP_PLL_SEL_VPLL
= 0,
207 DCLK_VOP_DIV_CON_MASK
= 0xff,
208 DCLK_VOP_DIV_CON_SHIFT
= 0,
211 CLK_SPI_PLL_SEL_MASK
= 1,
212 CLK_SPI_PLL_SEL_CPLL
= 0,
213 CLK_SPI_PLL_SEL_GPLL
= 1,
214 CLK_SPI_PLL_DIV_CON_MASK
= 0x7f,
215 CLK_SPI5_PLL_DIV_CON_SHIFT
= 8,
216 CLK_SPI5_PLL_SEL_SHIFT
= 15,
219 CLK_SPI1_PLL_SEL_SHIFT
= 15,
220 CLK_SPI1_PLL_DIV_CON_SHIFT
= 8,
221 CLK_SPI0_PLL_SEL_SHIFT
= 7,
222 CLK_SPI0_PLL_DIV_CON_SHIFT
= 0,
225 CLK_SPI4_PLL_SEL_SHIFT
= 15,
226 CLK_SPI4_PLL_DIV_CON_SHIFT
= 8,
227 CLK_SPI2_PLL_SEL_SHIFT
= 7,
228 CLK_SPI2_PLL_DIV_CON_SHIFT
= 0,
231 CLK_I2C_PLL_SEL_MASK
= 1,
232 CLK_I2C_PLL_SEL_CPLL
= 0,
233 CLK_I2C_PLL_SEL_GPLL
= 1,
234 CLK_I2C5_PLL_SEL_SHIFT
= 15,
235 CLK_I2C5_DIV_CON_SHIFT
= 8,
236 CLK_I2C1_PLL_SEL_SHIFT
= 7,
237 CLK_I2C1_DIV_CON_SHIFT
= 0,
240 CLK_I2C6_PLL_SEL_SHIFT
= 15,
241 CLK_I2C6_DIV_CON_SHIFT
= 8,
242 CLK_I2C2_PLL_SEL_SHIFT
= 7,
243 CLK_I2C2_DIV_CON_SHIFT
= 0,
246 CLK_I2C7_PLL_SEL_SHIFT
= 15,
247 CLK_I2C7_DIV_CON_SHIFT
= 8,
248 CLK_I2C3_PLL_SEL_SHIFT
= 7,
249 CLK_I2C3_DIV_CON_SHIFT
= 0,
251 /* CRU_SOFTRST_CON4 */
252 #define RESETN_DDR_REQ_SHIFT(ch) (8 + (ch) * 4)
253 #define RESETN_DDRPHY_REQ_SHIFT(ch) (9 + (ch) * 4)
256 #define VCO_MAX_KHZ (3200 * (MHz / KHz))
257 #define VCO_MIN_KHZ (800 * (MHz / KHz))
258 #define OUTPUT_MAX_KHZ (3200 * (MHz / KHz))
259 #define OUTPUT_MIN_KHZ (16 * (MHz / KHz))
261 /* the div restrictions of pll in integer mode,
262 * these are defined in * CRU_*PLL_CON0 or PMUCRU_*PLL_CON0
264 #define PLL_DIV_MIN 16
265 #define PLL_DIV_MAX 3200
267 /* How to calculate the PLL(from TRM V0.3 Part 1 Page 63):
268 * Formulas also embedded within the Fractional PLL Verilog model:
269 * If DSMPD = 1 (DSM is disabled, "integer mode")
270 * FOUTVCO = FREF / REFDIV * FBDIV
271 * FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2
273 * FOUTVCO = Fractional PLL non-divided output frequency
274 * FOUTPOSTDIV = Fractional PLL divided output frequency
275 * (output of second post divider)
276 * FREF = Fractional PLL input reference frequency, (the OSC_HZ 24MHz input)
277 * REFDIV = Fractional PLL input reference clock divider
278 * FBDIV = Integer value programmed into feedback divide
281 static void rkclk_set_pll(u32
*pll_con
, const struct pll_div
*div
)
283 /* All 8 PLLs have same VCO and output frequency range restrictions. */
284 u32 vco_khz
= OSC_HZ
/ 1000 * div
->fbdiv
/ div
->refdiv
;
285 u32 output_khz
= vco_khz
/ div
->postdiv1
/ div
->postdiv2
;
287 printk(BIOS_DEBUG
, "PLL at %p: fbdiv=%d, refdiv=%d, postdiv1=%d, "
288 "postdiv2=%d, vco=%u kHz, output=%u kHz\n",
289 pll_con
, div
->fbdiv
, div
->refdiv
, div
->postdiv1
,
290 div
->postdiv2
, vco_khz
, output_khz
);
291 assert(vco_khz
>= VCO_MIN_KHZ
&& vco_khz
<= VCO_MAX_KHZ
&&
292 output_khz
>= OUTPUT_MIN_KHZ
&& output_khz
<= OUTPUT_MAX_KHZ
&&
293 div
->fbdiv
>= PLL_DIV_MIN
&& div
->fbdiv
<= PLL_DIV_MAX
);
295 /* When power on or changing PLL setting,
296 * we must force PLL into slow mode to ensure output stable clock.
298 write32(&pll_con
[3], RK_CLRSETBITS(PLL_MODE_MASK
<< PLL_MODE_SHIFT
,
299 PLL_MODE_SLOW
<< PLL_MODE_SHIFT
));
301 /* use integer mode */
303 RK_CLRSETBITS(PLL_DSMPD_MASK
<< PLL_DSMPD_SHIFT
,
304 PLL_INTEGER_MODE
<< PLL_DSMPD_SHIFT
));
306 write32(&pll_con
[0], RK_CLRSETBITS(PLL_FBDIV_MASK
<< PLL_FBDIV_SHIFT
,
307 div
->fbdiv
<< PLL_FBDIV_SHIFT
));
309 RK_CLRSETBITS(PLL_POSTDIV2_MASK
<< PLL_POSTDIV2_SHIFT
|
310 PLL_POSTDIV1_MASK
<< PLL_POSTDIV1_SHIFT
|
311 PLL_REFDIV_MASK
| PLL_REFDIV_SHIFT
,
312 (div
->postdiv2
<< PLL_POSTDIV2_SHIFT
) |
313 (div
->postdiv1
<< PLL_POSTDIV1_SHIFT
) |
314 (div
->refdiv
<< PLL_REFDIV_SHIFT
)));
316 /* waiting for pll lock */
317 while (!(read32(&pll_con
[2]) & (1 << PLL_LOCK_STATUS_SHIFT
)))
320 /* pll enter normal mode */
321 write32(&pll_con
[3], RK_CLRSETBITS(PLL_MODE_MASK
<< PLL_MODE_SHIFT
,
322 PLL_MODE_NORM
<< PLL_MODE_SHIFT
));
326 * Configure the DPLL spread spectrum feature on memory clock.
327 * Configure sequence:
328 * 1. PLL been configured as frac mode, and DACPD should be set to 1'b0.
329 * 2. Configure DOWNSPERAD, SPREAD, DIVVAL(option: configure xPLL_CON5 with
330 * extern wave table).
331 * 3. set ssmod_disable_sscg = 1'b0, and set ssmod_bp = 1'b0.
332 * 4. Assert RESET = 1'b1 to SSMOD.
333 * 5. RESET = 1'b0 on SSMOD.
334 * 6. Adjust SPREAD/DIVVAL/DOWNSPREAD.
336 static void rkclk_set_dpllssc(struct pll_div
*dpll_cfg
)
340 assert(dpll_cfg
->refdiv
&& dpll_cfg
->refdiv
<= 6);
343 * Need to acquire ~30kHZ which is the target modulation frequency.
344 * The modulation frequency ~ 30kHz= OSC_HZ/revdiv/128/divval
345 * (the 128 is the number points in the query table).
347 divval
= OSC_HZ
/ 128 / (30 * KHz
) / dpll_cfg
->refdiv
;
351 * Make sure the output frequency isn't offset, set 0 for Fractional
352 * part of feedback divide.
354 write32(&cru_ptr
->dpll_con
[3],
355 RK_CLRSETBITS(PLL_DSMPD_MASK
<< PLL_DSMPD_SHIFT
,
356 PLL_FRAC_MODE
<< PLL_DSMPD_SHIFT
));
357 clrsetbits32(&cru_ptr
->dpll_con
[2],
358 PLL_FRACDIV_MASK
<< PLL_FRACDIV_SHIFT
,
359 0 << PLL_FRACDIV_SHIFT
);
362 * Configure SSC divval.
363 * Spread amplitude range = 0.1 * SPREAD[4:0] (%).
364 * The below 8 means SPREAD[4:0] that appears to mitigate EMI on boards
365 * tested. Center and down spread modulation amplitudes based on the
367 * SPREAD[4:0] Center Spread Down Spread
377 write32(&cru_ptr
->dpll_con
[4],
378 RK_CLRSETBITS(PLL_SSMOD_DIVVAL_MASK
<< PLL_SSMOD_DIVVAL_SHIFT
,
379 divval
<< PLL_SSMOD_DIVVAL_SHIFT
));
380 write32(&cru_ptr
->dpll_con
[4],
381 RK_CLRSETBITS(PLL_SSMOD_SPREADAMP_MASK
<<
382 PLL_SSMOD_SPREADAMP_SHIFT
,
383 8 << PLL_SSMOD_SPREADAMP_SHIFT
));
385 /* Enable SSC for DPLL */
386 write32(&cru_ptr
->dpll_con
[4],
387 RK_CLRBITS(PLL_SSMOD_BP_MASK
<< PLL_SSMOD_BP_SHIFT
|
388 PLL_SSMOD_DIS_SSCG_MASK
<< PLL_SSMOD_DIS_SSCG_SHIFT
));
390 /* Deassert reset SSMOD */
391 write32(&cru_ptr
->dpll_con
[4],
392 RK_CLRBITS(PLL_SSMOD_RESET_MASK
<< PLL_SSMOD_RESET_SHIFT
));
397 static int pll_para_config(u32 freq_hz
, struct pll_div
*div
)
399 u32 ref_khz
= OSC_HZ
/ KHz
, refdiv
, fbdiv
= 0;
400 u32 postdiv1
, postdiv2
= 1;
402 u32 diff_khz
, best_diff_khz
;
403 const u32 max_refdiv
= 63, max_fbdiv
= 3200, min_fbdiv
= 16;
404 const u32 max_postdiv1
= 7, max_postdiv2
= 7;
406 u32 freq_khz
= freq_hz
/ KHz
;
409 printk(BIOS_ERR
, "%s: the frequency can't be 0 Hz\n", __func__
);
413 postdiv1
= DIV_ROUND_UP(VCO_MIN_KHZ
, freq_khz
);
414 if (postdiv1
> max_postdiv1
) {
415 postdiv2
= DIV_ROUND_UP(postdiv1
, max_postdiv1
);
416 postdiv1
= DIV_ROUND_UP(postdiv1
, postdiv2
);
419 vco_khz
= freq_khz
* postdiv1
* postdiv2
;
421 if (vco_khz
< VCO_MIN_KHZ
|| vco_khz
> VCO_MAX_KHZ
||
422 postdiv2
> max_postdiv2
) {
423 printk(BIOS_ERR
, "%s: Cannot find out a supported VCO"
424 " for Frequency (%uHz).\n", __func__
, freq_hz
);
428 div
->postdiv1
= postdiv1
;
429 div
->postdiv2
= postdiv2
;
431 best_diff_khz
= vco_khz
;
432 for (refdiv
= 1; refdiv
< max_refdiv
&& best_diff_khz
; refdiv
++) {
433 fref_khz
= ref_khz
/ refdiv
;
435 fbdiv
= vco_khz
/ fref_khz
;
436 if ((fbdiv
>= max_fbdiv
) || (fbdiv
<= min_fbdiv
))
438 diff_khz
= vco_khz
- fbdiv
* fref_khz
;
439 if (fbdiv
+ 1 < max_fbdiv
&& diff_khz
> fref_khz
/ 2) {
441 diff_khz
= fref_khz
- diff_khz
;
444 if (diff_khz
>= best_diff_khz
)
447 best_diff_khz
= diff_khz
;
448 div
->refdiv
= refdiv
;
452 if (best_diff_khz
> 4 * (MHz
/KHz
)) {
453 printk(BIOS_ERR
, "%s: Failed to match output frequency %u, "
454 "difference is %u Hz,exceed 4MHZ\n", __func__
, freq_hz
,
455 best_diff_khz
* KHz
);
461 void rkclk_init(void)
467 /* some cru registers changed by bootrom, we'd better reset them to
468 * reset/default values described in TRM to avoid confusion in kernel.
469 * Please consider these three lines as a fix of bootrom bug.
471 write32(&cru_ptr
->clksel_con
[12], 0xffff4101);
472 write32(&cru_ptr
->clksel_con
[19], 0xffff033f);
473 write32(&cru_ptr
->clksel_con
[56], 0x00030003);
475 /* configure pmu pll(ppll) */
476 rkclk_set_pll(&pmucru_ptr
->ppll_con
[0], &ppll_init_cfg
);
478 /* configure pmu pclk */
479 pclk_div
= PPLL_HZ
/ PMU_PCLK_HZ
- 1;
480 assert((unsigned int)(PPLL_HZ
- (pclk_div
+ 1) * PMU_PCLK_HZ
) <= pclk_div
481 && pclk_div
<= 0x1f);
482 write32(&pmucru_ptr
->pmucru_clksel
[0],
483 RK_CLRSETBITS(PMU_PCLK_DIV_CON_MASK
<< PMU_PCLK_DIV_CON_SHIFT
,
484 pclk_div
<< PMU_PCLK_DIV_CON_SHIFT
));
486 /* configure gpll cpll */
487 rkclk_set_pll(&cru_ptr
->gpll_con
[0], &gpll_init_cfg
);
488 rkclk_set_pll(&cru_ptr
->cpll_con
[0], &cpll_init_cfg
);
490 /* configure perihp aclk, hclk, pclk */
491 aclk_div
= GPLL_HZ
/ PERIHP_ACLK_HZ
- 1;
492 assert((aclk_div
+ 1) * PERIHP_ACLK_HZ
== GPLL_HZ
&& aclk_div
<= 0x1f);
494 hclk_div
= PERIHP_ACLK_HZ
/ PERIHP_HCLK_HZ
- 1;
495 assert((hclk_div
+ 1) * PERIHP_HCLK_HZ
==
496 PERIHP_ACLK_HZ
&& (hclk_div
<= 0x3));
498 pclk_div
= PERIHP_ACLK_HZ
/ PERIHP_PCLK_HZ
- 1;
499 assert((pclk_div
+ 1) * PERIHP_PCLK_HZ
==
500 PERIHP_ACLK_HZ
&& (pclk_div
<= 0x7));
502 write32(&cru_ptr
->clksel_con
[14],
503 RK_CLRSETBITS(PCLK_PERIHP_DIV_CON_MASK
<<
504 PCLK_PERIHP_DIV_CON_SHIFT
|
505 HCLK_PERIHP_DIV_CON_MASK
<<
506 HCLK_PERIHP_DIV_CON_SHIFT
|
507 ACLK_PERIHP_PLL_SEL_MASK
<<
508 ACLK_PERIHP_PLL_SEL_SHIFT
|
509 ACLK_PERIHP_DIV_CON_MASK
<<
510 ACLK_PERIHP_DIV_CON_SHIFT
,
511 pclk_div
<< PCLK_PERIHP_DIV_CON_SHIFT
|
512 hclk_div
<< HCLK_PERIHP_DIV_CON_SHIFT
|
513 ACLK_PERIHP_PLL_SEL_GPLL
<<
514 ACLK_PERIHP_PLL_SEL_SHIFT
|
515 aclk_div
<< ACLK_PERIHP_DIV_CON_SHIFT
));
517 /* configure perilp0 aclk, hclk, pclk */
518 aclk_div
= GPLL_HZ
/ PERILP0_ACLK_HZ
- 1;
519 assert((aclk_div
+ 1) * PERILP0_ACLK_HZ
== GPLL_HZ
&& aclk_div
<= 0x1f);
521 hclk_div
= PERILP0_ACLK_HZ
/ PERILP0_HCLK_HZ
- 1;
522 assert((hclk_div
+ 1) * PERILP0_HCLK_HZ
==
523 PERILP0_ACLK_HZ
&& (hclk_div
<= 0x3));
525 pclk_div
= PERILP0_ACLK_HZ
/ PERILP0_PCLK_HZ
- 1;
526 assert((pclk_div
+ 1) * PERILP0_PCLK_HZ
==
527 PERILP0_ACLK_HZ
&& (pclk_div
<= 0x7));
529 write32(&cru_ptr
->clksel_con
[23],
530 RK_CLRSETBITS(PCLK_PERILP0_DIV_CON_MASK
<<
531 PCLK_PERILP0_DIV_CON_SHIFT
|
532 HCLK_PERILP0_DIV_CON_MASK
<<
533 HCLK_PERILP0_DIV_CON_SHIFT
|
534 ACLK_PERILP0_PLL_SEL_MASK
<<
535 ACLK_PERILP0_PLL_SEL_SHIFT
|
536 ACLK_PERILP0_DIV_CON_MASK
<<
537 ACLK_PERILP0_DIV_CON_SHIFT
,
538 pclk_div
<< PCLK_PERILP0_DIV_CON_SHIFT
|
539 hclk_div
<< HCLK_PERILP0_DIV_CON_SHIFT
|
540 ACLK_PERILP0_PLL_SEL_GPLL
<<
541 ACLK_PERILP0_PLL_SEL_SHIFT
|
542 aclk_div
<< ACLK_PERILP0_DIV_CON_SHIFT
));
544 /* perilp1 hclk select gpll as source */
545 hclk_div
= GPLL_HZ
/ PERILP1_HCLK_HZ
- 1;
546 assert((hclk_div
+ 1) * PERILP1_HCLK_HZ
==
547 GPLL_HZ
&& (hclk_div
<= 0x1f));
549 pclk_div
= PERILP1_HCLK_HZ
/ PERILP1_PCLK_HZ
- 1;
550 assert((pclk_div
+ 1) * PERILP1_PCLK_HZ
==
551 PERILP1_HCLK_HZ
&& (pclk_div
<= 0x7));
553 write32(&cru_ptr
->clksel_con
[25],
554 RK_CLRSETBITS(PCLK_PERILP1_DIV_CON_MASK
<<
555 PCLK_PERILP1_DIV_CON_SHIFT
|
556 HCLK_PERILP1_DIV_CON_MASK
<<
557 HCLK_PERILP1_DIV_CON_SHIFT
|
558 HCLK_PERILP1_PLL_SEL_MASK
<<
559 HCLK_PERILP1_PLL_SEL_SHIFT
,
560 pclk_div
<< PCLK_PERILP1_DIV_CON_SHIFT
|
561 hclk_div
<< HCLK_PERILP1_DIV_CON_SHIFT
|
562 HCLK_PERILP1_PLL_SEL_GPLL
<<
563 HCLK_PERILP1_PLL_SEL_SHIFT
));
566 void rkclk_configure_cpu(enum apll_frequencies freq
, enum cpu_cluster cluster
)
568 u32 aclkm_div
, atclk_div
, pclk_dbg_div
, apll_hz
;
569 int con_base
, parent
;
573 case CPU_CLUSTER_LITTLE
:
575 parent
= CLK_CORE_PLL_SEL_ALPLL
;
576 pll_con
= &cru_ptr
->apll_l_con
[0];
578 case CPU_CLUSTER_BIG
:
581 parent
= CLK_CORE_PLL_SEL_ABPLL
;
582 pll_con
= &cru_ptr
->apll_b_con
[0];
586 apll_hz
= apll_cfgs
[freq
]->freq
;
587 rkclk_set_pll(pll_con
, apll_cfgs
[freq
]);
589 aclkm_div
= DIV_ROUND_UP(apll_hz
, ACLKM_CORE_HZ
) - 1;
590 pclk_dbg_div
= DIV_ROUND_UP(apll_hz
, PCLK_DBG_HZ
) - 1;
591 atclk_div
= DIV_ROUND_UP(apll_hz
, ATCLK_CORE_HZ
) - 1;
593 write32(&cru_ptr
->clksel_con
[con_base
],
594 RK_CLRSETBITS(ACLKM_CORE_DIV_CON_MASK
<<
595 ACLKM_CORE_DIV_CON_SHIFT
|
596 CLK_CORE_PLL_SEL_MASK
<< CLK_CORE_PLL_SEL_SHIFT
|
597 CLK_CORE_DIV_MASK
<< CLK_CORE_DIV_SHIFT
,
598 aclkm_div
<< ACLKM_CORE_DIV_CON_SHIFT
|
599 parent
<< CLK_CORE_PLL_SEL_SHIFT
|
600 0 << CLK_CORE_DIV_SHIFT
));
602 write32(&cru_ptr
->clksel_con
[con_base
+ 1],
603 RK_CLRSETBITS(PCLK_DBG_DIV_MASK
<< PCLK_DBG_DIV_SHIFT
|
604 ATCLK_CORE_DIV_MASK
<< ATCLK_CORE_DIV_SHIFT
,
605 pclk_dbg_div
<< PCLK_DBG_DIV_SHIFT
|
606 atclk_div
<< ATCLK_CORE_DIV_SHIFT
));
609 void rkclk_configure_ddr(unsigned int hz
)
611 struct pll_div dpll_cfg
;
613 /* IC ECO bug, need to set this register */
614 write32(&rk3399_pmusgrf
->ddr_rgn_con
[16], 0xc000c000);
616 /* clk_ddrc == DPLL = 24MHz / refdiv * fbdiv / postdiv1 / postdiv2 */
619 dpll_cfg
= (struct pll_div
)
620 {.refdiv
= 1, .fbdiv
= 50, .postdiv1
= 3, .postdiv2
= 2};
623 dpll_cfg
= (struct pll_div
)
624 {.refdiv
= 2, .fbdiv
= 100, .postdiv1
= 4, .postdiv2
= 1};
627 dpll_cfg
= (struct pll_div
)
628 {.refdiv
= 2, .fbdiv
= 111, .postdiv1
= 2, .postdiv2
= 1};
631 dpll_cfg
= (struct pll_div
)
632 {.refdiv
= 1, .fbdiv
= 100, .postdiv1
= 3, .postdiv2
= 1};
635 dpll_cfg
= (struct pll_div
)
636 {.refdiv
= 1, .fbdiv
= 116, .postdiv1
= 3, .postdiv2
= 1};
639 die("Unsupported SDRAM frequency, add to clock.c!");
641 rkclk_set_pll(&cru_ptr
->dpll_con
[0], &dpll_cfg
);
643 if (CONFIG(RK3399_SPREAD_SPECTRUM_DDR
))
644 rkclk_set_dpllssc(&dpll_cfg
);
647 void rkclk_ddr_reset(u32 ch
, u32 ctl
, u32 phy
)
649 write32(&cru_ptr
->softrst_con
[4], RK_CLRSETBITS(
650 1 << RESETN_DDR_REQ_SHIFT(ch
) | 1 << RESETN_DDRPHY_REQ_SHIFT(ch
),
651 ctl
<< RESETN_DDR_REQ_SHIFT(ch
) | phy
<< RESETN_DDRPHY_REQ_SHIFT(ch
)));
654 #define SPI_CLK_REG_VALUE(bus, clk_div) \
655 RK_CLRSETBITS(CLK_SPI_PLL_SEL_MASK << \
656 CLK_SPI ##bus## _PLL_SEL_SHIFT | \
657 CLK_SPI_PLL_DIV_CON_MASK << \
658 CLK_SPI ##bus## _PLL_DIV_CON_SHIFT, \
659 CLK_SPI_PLL_SEL_GPLL << \
660 CLK_SPI ##bus## _PLL_SEL_SHIFT | \
662 CLK_SPI ##bus## _PLL_DIV_CON_SHIFT)
664 void rkclk_configure_spi(unsigned int bus
, unsigned int hz
)
669 /* spi3 src clock from ppll, while spi0,1,2,4,5 src clock from gpll */
670 pll
= (bus
== 3) ? PPLL_HZ
: GPLL_HZ
;
671 src_clk_div
= pll
/ hz
;
672 assert((src_clk_div
- 1 <= 127) && (src_clk_div
* hz
== pll
));
676 write32(&cru_ptr
->clksel_con
[59],
677 SPI_CLK_REG_VALUE(0, src_clk_div
));
680 write32(&cru_ptr
->clksel_con
[59],
681 SPI_CLK_REG_VALUE(1, src_clk_div
));
684 write32(&cru_ptr
->clksel_con
[60],
685 SPI_CLK_REG_VALUE(2, src_clk_div
));
688 write32(&pmucru_ptr
->pmucru_clksel
[1],
689 RK_CLRSETBITS(SPI3_PLL_SEL_MASK
<< SPI3_PLL_SEL_SHIFT
|
690 SPI3_DIV_CON_MASK
<< SPI3_DIV_CON_SHIFT
,
691 SPI3_PLL_SEL_PPLL
<< SPI3_PLL_SEL_SHIFT
|
692 (src_clk_div
- 1) << SPI3_DIV_CON_SHIFT
));
695 write32(&cru_ptr
->clksel_con
[60],
696 SPI_CLK_REG_VALUE(4, src_clk_div
));
699 write32(&cru_ptr
->clksel_con
[58],
700 SPI_CLK_REG_VALUE(5, src_clk_div
));
703 printk(BIOS_ERR
, "do not support this spi bus\n");
707 #define I2C_CLK_REG_VALUE(bus, clk_div) \
708 RK_CLRSETBITS(I2C_DIV_CON_MASK << \
709 CLK_I2C ##bus## _DIV_CON_SHIFT | \
710 CLK_I2C_PLL_SEL_MASK << \
711 CLK_I2C ##bus## _PLL_SEL_SHIFT, \
713 CLK_I2C ##bus## _DIV_CON_SHIFT | \
714 CLK_I2C_PLL_SEL_GPLL << \
715 CLK_I2C ##bus## _PLL_SEL_SHIFT)
716 #define PMU_I2C_CLK_REG_VALUE(bus, clk_div) \
717 RK_CLRSETBITS(I2C_DIV_CON_MASK << I2C ##bus## _DIV_CON_SHIFT, \
718 (clk_div - 1) << I2C ##bus## _DIV_CON_SHIFT)
720 uint32_t rkclk_i2c_clock_for_bus(unsigned int bus
)
722 int src_clk_div
, pll
, freq
;
724 /* i2c0,4,8 src clock from ppll, i2c1,2,3,5,6,7 src clock from gpll */
725 if (bus
== 0 || bus
== 4 || bus
== 8) {
732 src_clk_div
= pll
/ freq
;
733 assert((src_clk_div
- 1 <= 127) && (src_clk_div
* freq
== pll
));
737 write32(&pmucru_ptr
->pmucru_clksel
[2],
738 PMU_I2C_CLK_REG_VALUE(0, src_clk_div
));
741 write32(&cru_ptr
->clksel_con
[61],
742 I2C_CLK_REG_VALUE(1, src_clk_div
));
745 write32(&cru_ptr
->clksel_con
[62],
746 I2C_CLK_REG_VALUE(2, src_clk_div
));
749 write32(&cru_ptr
->clksel_con
[63],
750 I2C_CLK_REG_VALUE(3, src_clk_div
));
753 write32(&pmucru_ptr
->pmucru_clksel
[3],
754 PMU_I2C_CLK_REG_VALUE(4, src_clk_div
));
757 write32(&cru_ptr
->clksel_con
[61],
758 I2C_CLK_REG_VALUE(5, src_clk_div
));
761 write32(&cru_ptr
->clksel_con
[62],
762 I2C_CLK_REG_VALUE(6, src_clk_div
));
765 write32(&cru_ptr
->clksel_con
[63],
766 I2C_CLK_REG_VALUE(7, src_clk_div
));
769 write32(&pmucru_ptr
->pmucru_clksel
[2],
770 PMU_I2C_CLK_REG_VALUE(8, src_clk_div
));
773 die("unknown i2c bus\n");
779 void rkclk_configure_i2s(unsigned int hz
)
785 * clk_i2s0_sel: divider output from fraction
786 * clk_i2s0_pll_sel source clock: cpll
787 * clk_i2s0_div_con: 1 (div+1)
789 write32(&cru_ptr
->clksel_con
[28],
790 RK_CLRSETBITS(3 << 8 | 1 << 7 | 0x7f << 0,
791 1 << 8 | 0 << 7 | 0 << 0));
793 /* make sure and enable i2s0 path gates */
794 write32(&cru_ptr
->clkgate_con
[8],
795 RK_CLRBITS(1 << 12 | 1 << 5 | 1 << 4 | 1 << 3));
797 /* set frac divider */
798 v
= gcd(CPLL_HZ
, hz
);
799 n
= (CPLL_HZ
/ v
) & (0xffff);
800 d
= (hz
/ v
) & (0xffff);
801 assert(hz
== (u64
)CPLL_HZ
* d
/ n
);
802 write32(&cru_ptr
->clksel_con
[96], d
<< 16 | n
);
805 * clk_i2sout_sel clk_i2s
806 * clk_i2s_ch_sel: clk_i2s0
808 write32(&cru_ptr
->clksel_con
[31],
809 RK_CLRSETBITS(1 << 2 | 3 << 0,
813 void rkclk_configure_saradc(unsigned int hz
)
817 /* saradc src clk from 24MHz */
818 src_clk_div
= 24 * MHz
/ hz
;
819 assert((src_clk_div
- 1 <= 255) && (src_clk_div
* hz
== 24 * MHz
));
821 write32(&cru_ptr
->clksel_con
[26],
822 RK_CLRSETBITS(CLK_SARADC_DIV_CON_MASK
<<
823 CLK_SARADC_DIV_CON_SHIFT
,
824 (src_clk_div
- 1) << CLK_SARADC_DIV_CON_SHIFT
));
827 void rkclk_configure_vop_aclk(u32 vop_id
, u32 aclk_hz
)
830 void *reg_addr
= vop_id
? &cru_ptr
->clksel_con
[48] :
831 &cru_ptr
->clksel_con
[47];
833 /* vop aclk source clk: cpll */
834 div
= CPLL_HZ
/ aclk_hz
;
835 assert((div
- 1 <= 31) && (div
* aclk_hz
== CPLL_HZ
));
837 write32(reg_addr
, RK_CLRSETBITS(
838 ACLK_VOP_PLL_SEL_MASK
<< ACLK_VOP_PLL_SEL_SHIFT
|
839 ACLK_VOP_DIV_CON_MASK
<< ACLK_VOP_DIV_CON_SHIFT
,
840 ACLK_VOP_PLL_SEL_CPLL
<< ACLK_VOP_PLL_SEL_SHIFT
|
841 (div
- 1) << ACLK_VOP_DIV_CON_SHIFT
));
844 int rkclk_configure_vop_dclk(u32 vop_id
, u32 dclk_hz
)
846 struct pll_div vpll_config
= {0};
847 void *reg_addr
= vop_id
? &cru_ptr
->clksel_con
[50] :
848 &cru_ptr
->clksel_con
[49];
850 /* vop dclk source from vpll, and equals to vpll(means div == 1) */
851 if (pll_para_config(dclk_hz
, &vpll_config
))
854 rkclk_set_pll(&cru_ptr
->vpll_con
[0], &vpll_config
);
856 write32(reg_addr
, RK_CLRSETBITS(
857 DCLK_VOP_DCLK_SEL_MASK
<< DCLK_VOP_DCLK_SEL_SHIFT
|
858 DCLK_VOP_PLL_SEL_MASK
<< DCLK_VOP_PLL_SEL_SHIFT
|
859 DCLK_VOP_DIV_CON_MASK
<< DCLK_VOP_DIV_CON_SHIFT
,
860 DCLK_VOP_DCLK_SEL_DIVOUT
<< DCLK_VOP_DCLK_SEL_SHIFT
|
861 DCLK_VOP_PLL_SEL_VPLL
<< DCLK_VOP_PLL_SEL_SHIFT
|
862 (1 - 1) << DCLK_VOP_DIV_CON_SHIFT
));
867 void rkclk_configure_tsadc(unsigned int hz
)
871 /* use 24M as src clock */
872 src_clk_div
= OSC_HZ
/ hz
;
873 assert((src_clk_div
- 1 <= 1023) && (src_clk_div
* hz
== OSC_HZ
));
875 write32(&cru_ptr
->clksel_con
[27], RK_CLRSETBITS(
876 CLK_TSADC_DIV_CON_MASK
<< CLK_TSADC_DIV_CON_SHIFT
|
877 CLK_TSADC_SEL_MASK
<< CLK_TSADC_SEL_SHIFT
,
878 src_clk_div
<< CLK_TSADC_DIV_CON_SHIFT
|
879 CLK_TSADC_SEL_X24M
<< CLK_TSADC_SEL_SHIFT
));
882 void rkclk_configure_emmc(void)
885 int aclk_emmc
= 148500*KHz
;
886 int clk_emmc
= 148500*KHz
;
888 /* Select aclk_emmc source from GPLL */
889 src_clk_div
= GPLL_HZ
/ aclk_emmc
;
890 assert((src_clk_div
- 1 <= 31) && (src_clk_div
* aclk_emmc
== GPLL_HZ
));
892 write32(&cru_ptr
->clksel_con
[21],
893 RK_CLRSETBITS(ACLK_EMMC_PLL_SEL_MASK
<<
894 ACLK_EMMC_PLL_SEL_SHIFT
|
895 ACLK_EMMC_DIV_CON_MASK
<< ACLK_EMMC_DIV_CON_SHIFT
,
896 ACLK_EMMC_PLL_SEL_GPLL
<<
897 ACLK_EMMC_PLL_SEL_SHIFT
|
898 (src_clk_div
- 1) << ACLK_EMMC_DIV_CON_SHIFT
));
900 /* Select clk_emmc source from GPLL too */
901 src_clk_div
= GPLL_HZ
/ clk_emmc
;
902 assert((src_clk_div
- 1 <= 127) && (src_clk_div
* clk_emmc
== GPLL_HZ
));
904 write32(&cru_ptr
->clksel_con
[22],
905 RK_CLRSETBITS(CLK_EMMC_PLL_MASK
<< CLK_EMMC_PLL_SHIFT
|
906 CLK_EMMC_DIV_CON_MASK
<< CLK_EMMC_DIV_CON_SHIFT
,
907 CLK_EMMC_PLL_SEL_GPLL
<< CLK_EMMC_PLL_SHIFT
|
908 (src_clk_div
- 1) << CLK_EMMC_DIV_CON_SHIFT
));
911 int rkclk_was_watchdog_reset(void)
913 /* Bits 5 and 4 are "second" and "first" global watchdog reset. */
914 return read32(&cru_ptr
->glb_rst_st
) & 0x30;
917 void rkclk_configure_edp(unsigned int hz
)
921 src_clk_div
= CPLL_HZ
/ hz
;
922 assert((src_clk_div
- 1 <= 63) && (src_clk_div
* hz
== CPLL_HZ
));
924 write32(&cru_ptr
->clksel_con
[44],
925 RK_CLRSETBITS(CLK_PCLK_EDP_PLL_SEL_MASK
<<
926 CLK_PCLK_EDP_PLL_SEL_SHIFT
|
927 CLK_PCLK_EDP_DIV_CON_MASK
<<
928 CLK_PCLK_EDP_DIV_CON_SHIFT
,
929 CLK_PCLK_EDP_PLL_SEL_CPLL
<<
930 CLK_PCLK_EDP_PLL_SEL_SHIFT
|
932 CLK_PCLK_EDP_DIV_CON_SHIFT
));
935 void rkclk_configure_mipi(void)
937 /* Enable clk_mipidphy_ref and clk_mipidphy_cfg */
938 write32(&cru_ptr
->clkgate_con
[11],
939 RK_CLRBITS(1 << 14 | 1 << 15));
940 /* Enable pclk_mipi_dsi0 */
941 write32(&cru_ptr
->clkgate_con
[29],