blob: 97fdd099ef39a04e6f151cbe63c3bdb40565ae25 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0
Andy Yan6d95cd52017-06-01 18:00:36 +08002/*
3 * (C) Copyright 2016 Rockchip Electronics Co., Ltd
4 * Author: Andy Yan <andy.yan@rock-chips.com>
Andy Yan6d95cd52017-06-01 18:00:36 +08005 */
6
7#include <common.h>
David Wu0f106cc2017-09-20 14:28:18 +08008#include <bitfield.h>
Andy Yan6d95cd52017-06-01 18:00:36 +08009#include <clk-uclass.h>
10#include <dm.h>
11#include <errno.h>
12#include <syscon.h>
13#include <asm/io.h>
Kever Yang9fbe17c2019-03-28 11:01:23 +080014#include <asm/arch-rockchip/clock.h>
15#include <asm/arch-rockchip/cru_rv1108.h>
16#include <asm/arch-rockchip/hardware.h>
Andy Yan6d95cd52017-06-01 18:00:36 +080017#include <dm/lists.h>
18#include <dt-bindings/clock/rv1108-cru.h>
19
Otavio Salvador3afae5e2018-11-30 11:34:12 -020020DECLARE_GLOBAL_DATA_PTR;
21
Andy Yan6d95cd52017-06-01 18:00:36 +080022enum {
23 VCO_MAX_HZ = 2400U * 1000000,
24 VCO_MIN_HZ = 600 * 1000000,
25 OUTPUT_MAX_HZ = 2400U * 1000000,
26 OUTPUT_MIN_HZ = 24 * 1000000,
27};
28
Andy Yan6d95cd52017-06-01 18:00:36 +080029#define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1))
30
31#define PLL_DIVISORS(hz, _refdiv, _postdiv1, _postdiv2) {\
32 .refdiv = _refdiv,\
33 .fbdiv = (u32)((u64)hz * _refdiv * _postdiv1 * _postdiv2 / OSC_HZ),\
34 .postdiv1 = _postdiv1, .postdiv2 = _postdiv2};\
35 _Static_assert(((u64)hz * _refdiv * _postdiv1 * _postdiv2 / OSC_HZ) *\
36 OSC_HZ / (_refdiv * _postdiv1 * _postdiv2) == hz,\
37 #hz "Hz cannot be hit with PLL "\
38 "divisors on line " __stringify(__LINE__));
39
Otavio Salvador3afae5e2018-11-30 11:34:12 -020040static const struct pll_div apll_init_cfg = PLL_DIVISORS(APLL_HZ, 1, 3, 1);
41static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 2, 2, 1);
42
David Wu0f106cc2017-09-20 14:28:18 +080043/* use integer mode */
Andy Yan6d95cd52017-06-01 18:00:36 +080044static inline int rv1108_pll_id(enum rk_clk_id clk_id)
45{
46 int id = 0;
47
48 switch (clk_id) {
49 case CLK_ARM:
50 case CLK_DDR:
51 id = clk_id - 1;
52 break;
53 case CLK_GENERAL:
54 id = 2;
55 break;
56 default:
57 printf("invalid pll id:%d\n", clk_id);
58 id = -1;
59 break;
60 }
61
62 return id;
63}
64
Otavio Salvador3afae5e2018-11-30 11:34:12 -020065static int rkclk_set_pll(struct rv1108_cru *cru, enum rk_clk_id clk_id,
66 const struct pll_div *div)
67{
68 int pll_id = rv1108_pll_id(clk_id);
69 struct rv1108_pll *pll = &cru->pll[pll_id];
70
71 /* All PLLs have same VCO and output frequency range restrictions. */
72 uint vco_hz = OSC_HZ / 1000 * div->fbdiv / div->refdiv * 1000;
73 uint output_hz = vco_hz / div->postdiv1 / div->postdiv2;
74
75 debug("PLL at %p: fb=%d, ref=%d, pst1=%d, pst2=%d, vco=%u Hz, output=%u Hz\n",
76 pll, div->fbdiv, div->refdiv, div->postdiv1,
77 div->postdiv2, vco_hz, output_hz);
78 assert(vco_hz >= VCO_MIN_HZ && vco_hz <= VCO_MAX_HZ &&
79 output_hz >= OUTPUT_MIN_HZ && output_hz <= OUTPUT_MAX_HZ);
80
81 /*
82 * When power on or changing PLL setting,
83 * we must force PLL into slow mode to ensure output stable clock.
84 */
85 rk_clrsetreg(&pll->con3, WORK_MODE_MASK,
86 WORK_MODE_SLOW << WORK_MODE_SHIFT);
87
88 /* use integer mode */
89 rk_setreg(&pll->con3, 1 << DSMPD_SHIFT);
90 /* Power down */
91 rk_setreg(&pll->con3, 1 << GLOBAL_POWER_DOWN_SHIFT);
92
93 rk_clrsetreg(&pll->con0, FBDIV_MASK, div->fbdiv << FBDIV_SHIFT);
94 rk_clrsetreg(&pll->con1, POSTDIV1_MASK | POSTDIV2_MASK | REFDIV_MASK,
95 (div->postdiv1 << POSTDIV1_SHIFT |
96 div->postdiv2 << POSTDIV2_SHIFT |
97 div->refdiv << REFDIV_SHIFT));
98 rk_clrsetreg(&pll->con2, FRACDIV_MASK,
99 (div->refdiv << REFDIV_SHIFT));
100
101 /* Power Up */
102 rk_clrreg(&pll->con3, 1 << GLOBAL_POWER_DOWN_SHIFT);
103
104 /* waiting for pll lock */
105 while (readl(&pll->con2) & (1 << LOCK_STA_SHIFT))
106 udelay(1);
107
108 /*
109 * set PLL into normal mode.
110 */
111 rk_clrsetreg(&pll->con3, WORK_MODE_MASK,
112 WORK_MODE_NORMAL << WORK_MODE_SHIFT);
113
114 return 0;
115}
116
Andy Yan6d95cd52017-06-01 18:00:36 +0800117static uint32_t rkclk_pll_get_rate(struct rv1108_cru *cru,
118 enum rk_clk_id clk_id)
119{
120 uint32_t refdiv, fbdiv, postdiv1, postdiv2;
121 uint32_t con0, con1, con3;
122 int pll_id = rv1108_pll_id(clk_id);
123 struct rv1108_pll *pll = &cru->pll[pll_id];
124 uint32_t freq;
125
126 con3 = readl(&pll->con3);
127
128 if (con3 & WORK_MODE_MASK) {
129 con0 = readl(&pll->con0);
130 con1 = readl(&pll->con1);
131 fbdiv = (con0 >> FBDIV_SHIFT) & FBDIV_MASK;
132 postdiv1 = (con1 & POSTDIV1_MASK) >> POSTDIV1_SHIFT;
133 postdiv2 = (con1 & POSTDIV2_MASK) >> POSTDIV2_SHIFT;
Otavio Salvador3afae5e2018-11-30 11:34:12 -0200134 refdiv = (con1 >> REFDIV_SHIFT) & REFDIV_MASK;
Andy Yan6d95cd52017-06-01 18:00:36 +0800135 freq = (24 * fbdiv / (refdiv * postdiv1 * postdiv2)) * 1000000;
136 } else {
137 freq = OSC_HZ;
138 }
139
140 return freq;
141}
142
143static int rv1108_mac_set_clk(struct rv1108_cru *cru, ulong rate)
144{
145 uint32_t con = readl(&cru->clksel_con[24]);
146 ulong pll_rate;
147 uint8_t div;
148
149 if ((con >> MAC_PLL_SEL_SHIFT) & MAC_PLL_SEL_GPLL)
150 pll_rate = rkclk_pll_get_rate(cru, CLK_GENERAL);
151 else
152 pll_rate = rkclk_pll_get_rate(cru, CLK_ARM);
153
154 /*default set 50MHZ for gmac*/
155 if (!rate)
156 rate = 50000000;
157
158 div = DIV_ROUND_UP(pll_rate, rate) - 1;
159 if (div <= 0x1f)
160 rk_clrsetreg(&cru->clksel_con[24], MAC_CLK_DIV_MASK,
161 div << MAC_CLK_DIV_SHIFT);
162 else
163 debug("Unsupported div for gmac:%d\n", div);
164
165 return DIV_TO_RATE(pll_rate, div);
166}
167
168static int rv1108_sfc_set_clk(struct rv1108_cru *cru, uint rate)
169{
170 u32 con = readl(&cru->clksel_con[27]);
171 u32 pll_rate;
172 u32 div;
173
174 if ((con >> SFC_PLL_SEL_SHIFT) && SFC_PLL_SEL_GPLL)
175 pll_rate = rkclk_pll_get_rate(cru, CLK_GENERAL);
176 else
177 pll_rate = rkclk_pll_get_rate(cru, CLK_DDR);
178
179 div = DIV_ROUND_UP(pll_rate, rate) - 1;
180 if (div <= 0x3f)
181 rk_clrsetreg(&cru->clksel_con[27], SFC_CLK_DIV_MASK,
182 div << SFC_CLK_DIV_SHIFT);
183 else
184 debug("Unsupported sfc clk rate:%d\n", rate);
185
186 return DIV_TO_RATE(pll_rate, div);
187}
188
David Wu0f106cc2017-09-20 14:28:18 +0800189static ulong rv1108_saradc_get_clk(struct rv1108_cru *cru)
190{
191 u32 div, val;
192
193 val = readl(&cru->clksel_con[22]);
194 div = bitfield_extract(val, CLK_SARADC_DIV_CON_SHIFT,
195 CLK_SARADC_DIV_CON_WIDTH);
196
197 return DIV_TO_RATE(OSC_HZ, div);
198}
199
200static ulong rv1108_saradc_set_clk(struct rv1108_cru *cru, uint hz)
201{
202 int src_clk_div;
203
204 src_clk_div = DIV_ROUND_UP(OSC_HZ, hz) - 1;
205 assert(src_clk_div < 128);
206
207 rk_clrsetreg(&cru->clksel_con[22],
208 CLK_SARADC_DIV_CON_MASK,
209 src_clk_div << CLK_SARADC_DIV_CON_SHIFT);
210
211 return rv1108_saradc_get_clk(cru);
212}
213
Otavio Salvador3afae5e2018-11-30 11:34:12 -0200214static ulong rv1108_aclk_vio1_get_clk(struct rv1108_cru *cru)
215{
216 u32 div, val;
217
218 val = readl(&cru->clksel_con[28]);
219 div = bitfield_extract(val, ACLK_VIO1_CLK_DIV_SHIFT,
220 CLK_VIO_DIV_CON_WIDTH);
221
222 return DIV_TO_RATE(GPLL_HZ, div);
223}
224
225static ulong rv1108_aclk_vio1_set_clk(struct rv1108_cru *cru, uint hz)
226{
227 int src_clk_div;
228
229 src_clk_div = DIV_ROUND_UP(GPLL_HZ, hz) - 1;
230 assert(src_clk_div < 32);
231
232 rk_clrsetreg(&cru->clksel_con[28],
233 ACLK_VIO1_CLK_DIV_MASK | ACLK_VIO1_PLL_SEL_MASK,
234 (src_clk_div << ACLK_VIO1_CLK_DIV_SHIFT) |
235 (VIO_PLL_SEL_GPLL << ACLK_VIO1_PLL_SEL_SHIFT));
236
237 return rv1108_aclk_vio1_get_clk(cru);
238}
239
240static ulong rv1108_aclk_vio0_get_clk(struct rv1108_cru *cru)
241{
242 u32 div, val;
243
244 val = readl(&cru->clksel_con[28]);
245 div = bitfield_extract(val, ACLK_VIO0_CLK_DIV_SHIFT,
246 CLK_VIO_DIV_CON_WIDTH);
247
248 return DIV_TO_RATE(GPLL_HZ, div);
249}
250
251static ulong rv1108_aclk_vio0_set_clk(struct rv1108_cru *cru, uint hz)
252{
253 int src_clk_div;
254
255 src_clk_div = DIV_ROUND_UP(GPLL_HZ, hz) - 1;
256 assert(src_clk_div < 32);
257
258 rk_clrsetreg(&cru->clksel_con[28],
259 ACLK_VIO0_CLK_DIV_MASK | ACLK_VIO0_PLL_SEL_MASK,
260 (src_clk_div << ACLK_VIO0_CLK_DIV_SHIFT) |
261 (VIO_PLL_SEL_GPLL << ACLK_VIO0_PLL_SEL_SHIFT));
262
263 /*HCLK_VIO default div = 4*/
264 rk_clrsetreg(&cru->clksel_con[29],
265 HCLK_VIO_CLK_DIV_MASK,
266 3 << HCLK_VIO_CLK_DIV_SHIFT);
267 /*PCLK_VIO default div = 4*/
268 rk_clrsetreg(&cru->clksel_con[29],
269 PCLK_VIO_CLK_DIV_MASK,
270 3 << PCLK_VIO_CLK_DIV_SHIFT);
271
272 return rv1108_aclk_vio0_get_clk(cru);
273}
274
275static ulong rv1108_dclk_vop_get_clk(struct rv1108_cru *cru)
276{
277 u32 div, val;
278
279 val = readl(&cru->clksel_con[32]);
280 div = bitfield_extract(val, DCLK_VOP_CLK_DIV_SHIFT,
281 DCLK_VOP_DIV_CON_WIDTH);
282
283 return DIV_TO_RATE(GPLL_HZ, div);
284}
285
286static ulong rv1108_dclk_vop_set_clk(struct rv1108_cru *cru, uint hz)
287{
288 int src_clk_div;
289
290 src_clk_div = DIV_ROUND_UP(GPLL_HZ, hz) - 1;
291 assert(src_clk_div < 64);
292
293 rk_clrsetreg(&cru->clksel_con[32],
294 DCLK_VOP_CLK_DIV_MASK | DCLK_VOP_PLL_SEL_MASK |
295 DCLK_VOP_SEL_SHIFT,
296 (src_clk_div << DCLK_VOP_CLK_DIV_SHIFT) |
297 (DCLK_VOP_PLL_SEL_GPLL << DCLK_VOP_PLL_SEL_SHIFT) |
298 (DCLK_VOP_SEL_PLL << DCLK_VOP_SEL_SHIFT));
299
300 return rv1108_dclk_vop_get_clk(cru);
301}
302
303static ulong rv1108_aclk_bus_get_clk(struct rv1108_cru *cru)
304{
305 u32 div, val;
306 ulong parent_rate = rkclk_pll_get_rate(cru, CLK_GENERAL);
307
308 val = readl(&cru->clksel_con[2]);
309 div = bitfield_extract(val, ACLK_BUS_DIV_CON_SHIFT,
310 ACLK_BUS_DIV_CON_WIDTH);
311
312 return DIV_TO_RATE(parent_rate, div);
313}
314
315static ulong rv1108_aclk_bus_set_clk(struct rv1108_cru *cru, uint hz)
316{
317 int src_clk_div;
318 ulong parent_rate = rkclk_pll_get_rate(cru, CLK_GENERAL);
319
320 src_clk_div = DIV_ROUND_UP(parent_rate, hz) - 1;
321 assert(src_clk_div < 32);
322
323 rk_clrsetreg(&cru->clksel_con[2],
324 ACLK_BUS_DIV_CON_MASK | ACLK_BUS_PLL_SEL_MASK,
325 (src_clk_div << ACLK_BUS_DIV_CON_SHIFT) |
326 (ACLK_BUS_PLL_SEL_GPLL << ACLK_BUS_PLL_SEL_SHIFT));
327
328 return rv1108_aclk_bus_get_clk(cru);
329}
330
331static ulong rv1108_aclk_peri_get_clk(struct rv1108_cru *cru)
332{
333 u32 div, val;
334 ulong parent_rate = rkclk_pll_get_rate(cru, CLK_GENERAL);
335
336 val = readl(&cru->clksel_con[23]);
337 div = bitfield_extract(val, ACLK_PERI_DIV_CON_SHIFT,
338 PERI_DIV_CON_WIDTH);
339
340 return DIV_TO_RATE(parent_rate, div);
341}
342
343static ulong rv1108_hclk_peri_get_clk(struct rv1108_cru *cru)
344{
345 u32 div, val;
346 ulong parent_rate = rkclk_pll_get_rate(cru, CLK_GENERAL);
347
348 val = readl(&cru->clksel_con[23]);
349 div = bitfield_extract(val, HCLK_PERI_DIV_CON_SHIFT,
350 PERI_DIV_CON_WIDTH);
351
352 return DIV_TO_RATE(parent_rate, div);
353}
354
355static ulong rv1108_pclk_peri_get_clk(struct rv1108_cru *cru)
356{
357 u32 div, val;
358 ulong parent_rate = rkclk_pll_get_rate(cru, CLK_GENERAL);
359
360 val = readl(&cru->clksel_con[23]);
361 div = bitfield_extract(val, PCLK_PERI_DIV_CON_SHIFT,
362 PERI_DIV_CON_WIDTH);
363
364 return DIV_TO_RATE(parent_rate, div);
365}
366
367static ulong rv1108_aclk_peri_set_clk(struct rv1108_cru *cru, uint hz)
368{
369 int src_clk_div;
370 ulong parent_rate = rkclk_pll_get_rate(cru, CLK_GENERAL);
371
372 src_clk_div = DIV_ROUND_UP(parent_rate, hz) - 1;
373 assert(src_clk_div < 32);
374
375 rk_clrsetreg(&cru->clksel_con[23],
376 ACLK_PERI_DIV_CON_MASK | ACLK_PERI_PLL_SEL_MASK,
377 (src_clk_div << ACLK_PERI_DIV_CON_SHIFT) |
378 (ACLK_PERI_PLL_SEL_GPLL << ACLK_PERI_PLL_SEL_SHIFT));
379
380 return rv1108_aclk_peri_get_clk(cru);
381}
382
383static ulong rv1108_hclk_peri_set_clk(struct rv1108_cru *cru, uint hz)
384{
385 int src_clk_div;
386 ulong parent_rate = rkclk_pll_get_rate(cru, CLK_GENERAL);
387
388 src_clk_div = DIV_ROUND_UP(parent_rate, hz) - 1;
389 assert(src_clk_div < 32);
390
391 rk_clrsetreg(&cru->clksel_con[23],
392 HCLK_PERI_DIV_CON_MASK,
393 (src_clk_div << HCLK_PERI_DIV_CON_SHIFT));
394
395 return rv1108_hclk_peri_get_clk(cru);
396}
397
398static ulong rv1108_pclk_peri_set_clk(struct rv1108_cru *cru, uint hz)
399{
400 int src_clk_div;
401 ulong parent_rate = rkclk_pll_get_rate(cru, CLK_GENERAL);
402
403 src_clk_div = DIV_ROUND_UP(parent_rate, hz) - 1;
404 assert(src_clk_div < 32);
405
406 rk_clrsetreg(&cru->clksel_con[23],
407 PCLK_PERI_DIV_CON_MASK,
408 (src_clk_div << PCLK_PERI_DIV_CON_SHIFT));
409
410 return rv1108_pclk_peri_get_clk(cru);
411}
412
413static ulong rv1108_i2c_get_clk(struct rv1108_cru *cru, ulong clk_id)
414{
415 u32 div, con;
416
417 switch (clk_id) {
418 case SCLK_I2C0_PMU:
419 con = readl(&cru->clksel_con[19]);
420 div = bitfield_extract(con, CLK_I2C0_DIV_CON_SHIFT,
421 I2C_DIV_CON_WIDTH);
422 break;
423 case SCLK_I2C1:
424 con = readl(&cru->clksel_con[19]);
425 div = bitfield_extract(con, CLK_I2C1_DIV_CON_SHIFT,
426 I2C_DIV_CON_WIDTH);
427 break;
428 case SCLK_I2C2:
429 con = readl(&cru->clksel_con[20]);
430 div = bitfield_extract(con, CLK_I2C2_DIV_CON_SHIFT,
431 I2C_DIV_CON_WIDTH);
432 break;
433 case SCLK_I2C3:
434 con = readl(&cru->clksel_con[20]);
435 div = bitfield_extract(con, CLK_I2C3_DIV_CON_SHIFT,
436 I2C_DIV_CON_WIDTH);
437 break;
438 default:
439 printf("do not support this i2c bus\n");
440 return -EINVAL;
441 }
442
443 return DIV_TO_RATE(GPLL_HZ, div);
444}
445
446static ulong rv1108_i2c_set_clk(struct rv1108_cru *cru, ulong clk_id, uint hz)
447{
448 int src_clk_div;
449
450 /* i2c0,4,8 src clock from ppll, i2c1,2,3,5,6,7 src clock from gpll*/
451 src_clk_div = GPLL_HZ / hz;
452 assert(src_clk_div - 1 <= 127);
453
454 switch (clk_id) {
455 case SCLK_I2C0_PMU:
456 rk_clrsetreg(&cru->clksel_con[19],
457 CLK_I2C0_DIV_CON_MASK | CLK_I2C1_PLL_SEL_MASK,
458 (src_clk_div << CLK_I2C0_DIV_CON_SHIFT) |
459 (CLK_I2C1_PLL_SEL_GPLL << CLK_I2C1_PLL_SEL_SHIFT));
460 break;
461 case SCLK_I2C1:
462 rk_clrsetreg(&cru->clksel_con[19],
463 CLK_I2C1_DIV_CON_MASK | CLK_I2C1_PLL_SEL_MASK,
464 (src_clk_div << CLK_I2C1_DIV_CON_SHIFT) |
465 (CLK_I2C1_PLL_SEL_GPLL << CLK_I2C1_PLL_SEL_SHIFT));
466 break;
467 case SCLK_I2C2:
468 rk_clrsetreg(&cru->clksel_con[20],
469 CLK_I2C2_DIV_CON_MASK | CLK_I2C3_PLL_SEL_MASK,
470 (src_clk_div << CLK_I2C2_DIV_CON_SHIFT) |
471 (CLK_I2C3_PLL_SEL_GPLL << CLK_I2C3_PLL_SEL_SHIFT));
472 break;
473 case SCLK_I2C3:
474 rk_clrsetreg(&cru->clksel_con[20],
475 CLK_I2C3_DIV_CON_MASK | CLK_I2C3_PLL_SEL_MASK,
476 (src_clk_div << CLK_I2C3_DIV_CON_SHIFT) |
477 (CLK_I2C3_PLL_SEL_GPLL << CLK_I2C3_PLL_SEL_SHIFT));
478 break;
479 default:
480 printf("do not support this i2c bus\n");
481 return -EINVAL;
482 }
483
484 return rv1108_i2c_get_clk(cru, clk_id);
485}
486
487static ulong rv1108_mmc_get_clk(struct rv1108_cru *cru)
488{
489 u32 div, con;
490 ulong mmc_clk;
491
492 con = readl(&cru->clksel_con[26]);
493 div = bitfield_extract(con, EMMC_CLK_DIV_SHIFT, 8);
494
495 con = readl(&cru->clksel_con[25]);
496
497 if ((con & EMMC_PLL_SEL_MASK) >> EMMC_PLL_SEL_SHIFT == EMMC_PLL_SEL_OSC)
498 mmc_clk = DIV_TO_RATE(OSC_HZ, div) / 2;
499 else
500 mmc_clk = DIV_TO_RATE(GPLL_HZ, div) / 2;
501
502 debug("%s div %d get_clk %ld\n", __func__, div, mmc_clk);
503 return mmc_clk;
504}
505
506static ulong rv1108_mmc_set_clk(struct rv1108_cru *cru, ulong rate)
507{
508 int div;
509 u32 pll_rate;
510
511 div = DIV_ROUND_UP(rkclk_pll_get_rate(cru, CLK_GENERAL), rate);
512
513 if (div < 127) {
514 debug("%s source gpll\n", __func__);
515 rk_clrsetreg(&cru->clksel_con[25], EMMC_PLL_SEL_MASK,
516 (EMMC_PLL_SEL_GPLL << EMMC_PLL_SEL_SHIFT));
517 pll_rate = rkclk_pll_get_rate(cru, CLK_GENERAL);
518 } else {
519 debug("%s source 24m\n", __func__);
520 rk_clrsetreg(&cru->clksel_con[25], EMMC_PLL_SEL_MASK,
521 (EMMC_PLL_SEL_OSC << EMMC_PLL_SEL_SHIFT));
522 pll_rate = OSC_HZ;
523 }
524
525 div = DIV_ROUND_UP(pll_rate / 2, rate);
526 rk_clrsetreg(&cru->clksel_con[26], EMMC_CLK_DIV_MASK,
527 ((div - 1) << EMMC_CLK_DIV_SHIFT));
528
529 debug("%s set_rate %ld div %d\n", __func__, rate, div);
530
531 return DIV_TO_RATE(pll_rate, div);
532}
533
Andy Yan6d95cd52017-06-01 18:00:36 +0800534static ulong rv1108_clk_get_rate(struct clk *clk)
535{
536 struct rv1108_clk_priv *priv = dev_get_priv(clk->dev);
537
538 switch (clk->id) {
539 case 0 ... 63:
540 return rkclk_pll_get_rate(priv->cru, clk->id);
David Wu0f106cc2017-09-20 14:28:18 +0800541 case SCLK_SARADC:
542 return rv1108_saradc_get_clk(priv->cru);
Otavio Salvador3afae5e2018-11-30 11:34:12 -0200543 case ACLK_VIO0:
544 return rv1108_aclk_vio0_get_clk(priv->cru);
545 case ACLK_VIO1:
546 return rv1108_aclk_vio1_get_clk(priv->cru);
547 case DCLK_VOP:
548 return rv1108_dclk_vop_get_clk(priv->cru);
549 case ACLK_PRE:
550 return rv1108_aclk_bus_get_clk(priv->cru);
551 case ACLK_PERI:
552 return rv1108_aclk_peri_get_clk(priv->cru);
553 case HCLK_PERI:
554 return rv1108_hclk_peri_get_clk(priv->cru);
555 case PCLK_PERI:
556 return rv1108_pclk_peri_get_clk(priv->cru);
557 case SCLK_I2C0_PMU:
558 case SCLK_I2C1:
559 case SCLK_I2C2:
560 case SCLK_I2C3:
561 return rv1108_i2c_get_clk(priv->cru, clk->id);
562 case HCLK_EMMC:
563 case SCLK_EMMC:
564 case SCLK_EMMC_SAMPLE:
565 return rv1108_mmc_get_clk(priv->cru);
Andy Yan6d95cd52017-06-01 18:00:36 +0800566 default:
567 return -ENOENT;
568 }
569}
570
571static ulong rv1108_clk_set_rate(struct clk *clk, ulong rate)
572{
573 struct rv1108_clk_priv *priv = dev_get_priv(clk->dev);
574 ulong new_rate;
575
576 switch (clk->id) {
577 case SCLK_MAC:
578 new_rate = rv1108_mac_set_clk(priv->cru, rate);
579 break;
580 case SCLK_SFC:
581 new_rate = rv1108_sfc_set_clk(priv->cru, rate);
582 break;
David Wu0f106cc2017-09-20 14:28:18 +0800583 case SCLK_SARADC:
584 new_rate = rv1108_saradc_set_clk(priv->cru, rate);
585 break;
Otavio Salvador3afae5e2018-11-30 11:34:12 -0200586 case ACLK_VIO0:
587 new_rate = rv1108_aclk_vio0_set_clk(priv->cru, rate);
588 break;
589 case ACLK_VIO1:
590 new_rate = rv1108_aclk_vio1_set_clk(priv->cru, rate);
591 break;
592 case DCLK_VOP:
593 new_rate = rv1108_dclk_vop_set_clk(priv->cru, rate);
594 break;
595 case ACLK_PRE:
596 new_rate = rv1108_aclk_bus_set_clk(priv->cru, rate);
597 break;
598 case ACLK_PERI:
599 new_rate = rv1108_aclk_peri_set_clk(priv->cru, rate);
600 break;
601 case HCLK_PERI:
602 new_rate = rv1108_hclk_peri_set_clk(priv->cru, rate);
603 break;
604 case PCLK_PERI:
605 new_rate = rv1108_pclk_peri_set_clk(priv->cru, rate);
606 break;
607 case SCLK_I2C0_PMU:
608 case SCLK_I2C1:
609 case SCLK_I2C2:
610 case SCLK_I2C3:
611 new_rate = rv1108_i2c_set_clk(priv->cru, clk->id, rate);
612 break;
613 case HCLK_EMMC:
614 case SCLK_EMMC:
615 new_rate = rv1108_mmc_set_clk(priv->cru, rate);
616 break;
Andy Yan6d95cd52017-06-01 18:00:36 +0800617 default:
618 return -ENOENT;
619 }
620
621 return new_rate;
622}
623
624static const struct clk_ops rv1108_clk_ops = {
625 .get_rate = rv1108_clk_get_rate,
626 .set_rate = rv1108_clk_set_rate,
627};
628
629static void rkclk_init(struct rv1108_cru *cru)
630{
Otavio Salvador3afae5e2018-11-30 11:34:12 -0200631 unsigned int apll, dpll, gpll;
632 unsigned int aclk_bus, aclk_peri, hclk_peri, pclk_peri;
633
634 aclk_bus = rv1108_aclk_bus_set_clk(cru, ACLK_BUS_HZ / 2);
635 aclk_peri = rv1108_aclk_peri_set_clk(cru, ACLK_PERI_HZ / 2);
636 hclk_peri = rv1108_hclk_peri_set_clk(cru, HCLK_PERI_HZ / 2);
637 pclk_peri = rv1108_pclk_peri_set_clk(cru, PCLK_PERI_HZ / 2);
638 rv1108_aclk_vio0_set_clk(cru, 297000000);
639 rv1108_aclk_vio1_set_clk(cru, 297000000);
640
641 /* configure apll */
642 rkclk_set_pll(cru, CLK_ARM, &apll_init_cfg);
643 rkclk_set_pll(cru, CLK_GENERAL, &gpll_init_cfg);
644 aclk_bus = rv1108_aclk_bus_set_clk(cru, ACLK_BUS_HZ);
645 aclk_peri = rv1108_aclk_peri_set_clk(cru, ACLK_PERI_HZ);
646 hclk_peri = rv1108_hclk_peri_set_clk(cru, HCLK_PERI_HZ);
647 pclk_peri = rv1108_pclk_peri_set_clk(cru, PCLK_PERI_HZ);
648
649 apll = rkclk_pll_get_rate(cru, CLK_ARM);
650 dpll = rkclk_pll_get_rate(cru, CLK_DDR);
651 gpll = rkclk_pll_get_rate(cru, CLK_GENERAL);
Andy Yan6d95cd52017-06-01 18:00:36 +0800652
653 rk_clrsetreg(&cru->clksel_con[0], CORE_CLK_DIV_MASK,
654 0 << MAC_CLK_DIV_SHIFT);
655
656 printf("APLL: %d DPLL:%d GPLL:%d\n", apll, dpll, gpll);
Otavio Salvador3afae5e2018-11-30 11:34:12 -0200657 printf("ACLK_BUS: %d ACLK_PERI:%d HCLK_PERI:%d PCLK_PERI:%d\n",
658 aclk_bus, aclk_peri, hclk_peri, pclk_peri);
Andy Yan6d95cd52017-06-01 18:00:36 +0800659}
660
Kever Yang216cccb2018-04-24 11:27:08 +0800661static int rv1108_clk_ofdata_to_platdata(struct udevice *dev)
Andy Yan6d95cd52017-06-01 18:00:36 +0800662{
663 struct rv1108_clk_priv *priv = dev_get_priv(dev);
664
Kever Yanga70fe322018-02-11 11:53:10 +0800665 priv->cru = dev_read_addr_ptr(dev);
Andy Yan6d95cd52017-06-01 18:00:36 +0800666
Kever Yang216cccb2018-04-24 11:27:08 +0800667 return 0;
668}
669
670static int rv1108_clk_probe(struct udevice *dev)
671{
672 struct rv1108_clk_priv *priv = dev_get_priv(dev);
673
Andy Yan6d95cd52017-06-01 18:00:36 +0800674 rkclk_init(priv->cru);
675
676 return 0;
677}
678
679static int rv1108_clk_bind(struct udevice *dev)
680{
681 int ret;
Heiko Stuebnerc82c06d2019-11-09 00:06:29 +0100682 struct udevice *sys_child;
Kever Yang4fbb6c22017-11-03 15:16:13 +0800683 struct sysreset_reg *priv;
Andy Yan6d95cd52017-06-01 18:00:36 +0800684
685 /* The reset driver does not have a device node, so bind it here */
Kever Yang4fbb6c22017-11-03 15:16:13 +0800686 ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
687 &sys_child);
688 if (ret) {
689 debug("Warning: No sysreset driver: ret=%d\n", ret);
690 } else {
691 priv = malloc(sizeof(struct sysreset_reg));
692 priv->glb_srst_fst_value = offsetof(struct rv1108_cru,
693 glb_srst_fst_val);
694 priv->glb_srst_snd_value = offsetof(struct rv1108_cru,
695 glb_srst_snd_val);
696 sys_child->priv = priv;
697 }
Andy Yan6d95cd52017-06-01 18:00:36 +0800698
Heiko Stuebner416f8d32019-11-09 00:06:30 +0100699#if CONFIG_IS_ENABLED(RESET_ROCKCHIP)
Heiko Stuebnerc82c06d2019-11-09 00:06:29 +0100700 ret = offsetof(struct rv1108_cru, softrst_con[0]);
Elaine Zhang432976f2017-12-19 18:22:38 +0800701 ret = rockchip_reset_bind(dev, ret, 13);
702 if (ret)
703 debug("Warning: software reset driver bind faile\n");
704#endif
705
Andy Yan6d95cd52017-06-01 18:00:36 +0800706 return 0;
707}
708
709static const struct udevice_id rv1108_clk_ids[] = {
710 { .compatible = "rockchip,rv1108-cru" },
711 { }
712};
713
714U_BOOT_DRIVER(clk_rv1108) = {
715 .name = "clk_rv1108",
716 .id = UCLASS_CLK,
717 .of_match = rv1108_clk_ids,
718 .priv_auto_alloc_size = sizeof(struct rv1108_clk_priv),
Andy Yan6d95cd52017-06-01 18:00:36 +0800719 .ops = &rv1108_clk_ops,
720 .bind = rv1108_clk_bind,
Otavio Salvador3afae5e2018-11-30 11:34:12 -0200721 .ofdata_to_platdata = rv1108_clk_ofdata_to_platdata,
Andy Yan6d95cd52017-06-01 18:00:36 +0800722 .probe = rv1108_clk_probe,
723};