Merge tag 'video-for-v2020.01-rc2' of https://gitlab.denx.de/u-boot/custodians/u...
[oweals/u-boot.git] / drivers / clk / rockchip / clk_rk3308.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * (C) Copyright 2017-2019 Rockchip Electronics Co., Ltd
4  */
5 #include <common.h>
6 #include <bitfield.h>
7 #include <clk-uclass.h>
8 #include <dm.h>
9 #include <div64.h>
10 #include <errno.h>
11 #include <syscon.h>
12 #include <asm/io.h>
13 #include <asm/arch/cru_rk3308.h>
14 #include <asm/arch-rockchip/clock.h>
15 #include <asm/arch-rockchip/hardware.h>
16 #include <dm/lists.h>
17 #include <dt-bindings/clock/rk3308-cru.h>
18
19 DECLARE_GLOBAL_DATA_PTR;
20
21 enum {
22         VCO_MAX_HZ      = 3200U * 1000000,
23         VCO_MIN_HZ      = 800 * 1000000,
24         OUTPUT_MAX_HZ   = 3200U * 1000000,
25         OUTPUT_MIN_HZ   = 24 * 1000000,
26 };
27
28 #define DIV_TO_RATE(input_rate, div)    ((input_rate) / ((div) + 1))
29
30 #define RK3308_CPUCLK_RATE(_rate, _aclk_div, _pclk_div)         \
31 {                                                               \
32         .rate   = _rate##U,                                     \
33         .aclk_div = _aclk_div,                                  \
34         .pclk_div = _pclk_div,                                  \
35 }
36
37 static struct rockchip_pll_rate_table rk3308_pll_rates[] = {
38         /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
39         RK3036_PLL_RATE(1300000000, 6, 325, 1, 1, 1, 0),
40         RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0),
41         RK3036_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0),
42         RK3036_PLL_RATE(748000000, 2, 187, 3, 1, 1, 0),
43 };
44
45 static struct rockchip_cpu_rate_table rk3308_cpu_rates[] = {
46         RK3308_CPUCLK_RATE(1200000000, 1, 5),
47         RK3308_CPUCLK_RATE(1008000000, 1, 5),
48         RK3308_CPUCLK_RATE(816000000, 1, 3),
49         RK3308_CPUCLK_RATE(600000000, 1, 3),
50         RK3308_CPUCLK_RATE(408000000, 1, 1),
51 };
52
53 static struct rockchip_pll_clock rk3308_pll_clks[] = {
54         [APLL] = PLL(pll_rk3328, PLL_APLL, RK3308_PLL_CON(0),
55                      RK3308_MODE_CON, 0, 10, 0, rk3308_pll_rates),
56         [DPLL] = PLL(pll_rk3328, PLL_DPLL, RK3308_PLL_CON(8),
57                      RK3308_MODE_CON, 2, 10, 0, NULL),
58         [VPLL0] = PLL(pll_rk3328, PLL_VPLL0, RK3308_PLL_CON(16),
59                       RK3308_MODE_CON, 4, 10, 0, NULL),
60         [VPLL1] = PLL(pll_rk3328, PLL_VPLL1, RK3308_PLL_CON(24),
61                       RK3308_MODE_CON, 6, 10, 0, NULL),
62 };
63
64 static ulong rk3308_armclk_set_clk(struct rk3308_clk_priv *priv, ulong hz)
65 {
66         struct rk3308_cru *cru = priv->cru;
67         const struct rockchip_cpu_rate_table *rate;
68         ulong old_rate;
69
70         rate = rockchip_get_cpu_settings(rk3308_cpu_rates, hz);
71         if (!rate) {
72                 printf("%s unsupport rate\n", __func__);
73                 return -EINVAL;
74         }
75
76         /*
77          * select apll as cpu/core clock pll source and
78          * set up dependent divisors for PERI and ACLK clocks.
79          * core hz : apll = 1:1
80          */
81         old_rate = rockchip_pll_get_rate(&rk3308_pll_clks[APLL],
82                                          priv->cru, APLL);
83         if (old_rate > hz) {
84                 if (rockchip_pll_set_rate(&rk3308_pll_clks[APLL],
85                                           priv->cru, APLL, hz))
86                         return -EINVAL;
87                 rk_clrsetreg(&cru->clksel_con[0],
88                              CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK |
89                              CORE_ACLK_DIV_MASK | CORE_DBG_DIV_MASK,
90                              rate->aclk_div << CORE_ACLK_DIV_SHIFT |
91                              rate->pclk_div << CORE_DBG_DIV_SHIFT |
92                              CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT |
93                              0 << CORE_DIV_CON_SHIFT);
94         } else if (old_rate < hz) {
95                 rk_clrsetreg(&cru->clksel_con[0],
96                              CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK |
97                              CORE_ACLK_DIV_MASK | CORE_DBG_DIV_MASK,
98                              rate->aclk_div << CORE_ACLK_DIV_SHIFT |
99                              rate->pclk_div << CORE_DBG_DIV_SHIFT |
100                              CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT |
101                              0 << CORE_DIV_CON_SHIFT);
102                 if (rockchip_pll_set_rate(&rk3308_pll_clks[APLL],
103                                           priv->cru, APLL, hz))
104                         return -EINVAL;
105         }
106
107         return rockchip_pll_get_rate(&rk3308_pll_clks[APLL], priv->cru, APLL);
108 }
109
110 static void rk3308_clk_get_pll_rate(struct rk3308_clk_priv *priv)
111 {
112         if (!priv->dpll_hz)
113                 priv->dpll_hz = rockchip_pll_get_rate(&rk3308_pll_clks[DPLL],
114                                                       priv->cru, DPLL);
115         if (!priv->vpll0_hz)
116                 priv->vpll0_hz = rockchip_pll_get_rate(&rk3308_pll_clks[VPLL0],
117                                                        priv->cru, VPLL0);
118         if (!priv->vpll1_hz)
119                 priv->vpll1_hz = rockchip_pll_get_rate(&rk3308_pll_clks[VPLL1],
120                                                        priv->cru, VPLL1);
121 }
122
123 static ulong rk3308_i2c_get_clk(struct clk *clk)
124 {
125         struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
126         struct rk3308_cru *cru = priv->cru;
127         u32 div, con, con_id;
128
129         switch (clk->id) {
130         case SCLK_I2C0:
131                 con_id = 25;
132                 break;
133         case SCLK_I2C1:
134                 con_id = 26;
135                 break;
136         case SCLK_I2C2:
137                 con_id = 27;
138                 break;
139         case SCLK_I2C3:
140                 con_id = 28;
141                 break;
142         default:
143                 printf("do not support this i2c bus\n");
144                 return -EINVAL;
145         }
146
147         con = readl(&cru->clksel_con[con_id]);
148         div = con >> CLK_I2C_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK;
149
150         return DIV_TO_RATE(priv->dpll_hz, div);
151 }
152
153 static ulong rk3308_i2c_set_clk(struct clk *clk, uint hz)
154 {
155         struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
156         struct rk3308_cru *cru = priv->cru;
157         u32 src_clk_div, con_id;
158
159         src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz);
160         assert(src_clk_div - 1 <= 127);
161
162         switch (clk->id) {
163         case SCLK_I2C0:
164                 con_id = 25;
165                 break;
166         case SCLK_I2C1:
167                 con_id = 26;
168                 break;
169         case SCLK_I2C2:
170                 con_id = 27;
171                 break;
172         case SCLK_I2C3:
173                 con_id = 28;
174                 break;
175         default:
176                 printf("do not support this i2c bus\n");
177                 return -EINVAL;
178         }
179         rk_clrsetreg(&cru->clksel_con[con_id],
180                      CLK_I2C_PLL_SEL_MASK | CLK_I2C_DIV_CON_MASK,
181                      CLK_I2C_PLL_SEL_DPLL << CLK_I2C_PLL_SEL_SHIFT |
182                      (src_clk_div - 1) << CLK_I2C_DIV_CON_SHIFT);
183
184         return rk3308_i2c_get_clk(clk);
185 }
186
187 static ulong rk3308_mac_set_clk(struct clk *clk, uint hz)
188 {
189         struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
190         struct rk3308_cru *cru = priv->cru;
191         u32 con = readl(&cru->clksel_con[43]);
192         ulong pll_rate;
193         u8 div;
194
195         if ((con >> MAC_PLL_SHIFT) & MAC_SEL_VPLL0)
196                 pll_rate = rockchip_pll_get_rate(&rk3308_pll_clks[VPLL0],
197                                                  priv->cru, VPLL0);
198         else if ((con >> MAC_PLL_SHIFT) & MAC_SEL_VPLL1)
199                 pll_rate = rockchip_pll_get_rate(&rk3308_pll_clks[VPLL1],
200                                                  priv->cru, VPLL1);
201         else
202                 pll_rate = rockchip_pll_get_rate(&rk3308_pll_clks[DPLL],
203                                                  priv->cru, DPLL);
204
205         /*default set 50MHZ for gmac*/
206         if (!hz)
207                 hz = 50000000;
208
209         div = DIV_ROUND_UP(pll_rate, hz) - 1;
210         assert(div < 32);
211         rk_clrsetreg(&cru->clksel_con[43], MAC_DIV_MASK,
212                      div << MAC_DIV_SHIFT);
213
214         return DIV_TO_RATE(pll_rate, div);
215 }
216
217 static int rk3308_mac_set_speed_clk(struct clk *clk, uint hz)
218 {
219         struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
220         struct rk3308_cru *cru = priv->cru;
221
222         if (hz != 2500000 && hz != 25000000) {
223                 debug("Unsupported mac speed:%d\n", hz);
224                 return -EINVAL;
225         }
226
227         rk_clrsetreg(&cru->clksel_con[43], MAC_CLK_SPEED_SEL_MASK,
228                      ((hz == 2500000) ? 0 : 1) << MAC_CLK_SPEED_SEL_SHIFT);
229
230         return 0;
231 }
232
233 static ulong rk3308_mmc_get_clk(struct clk *clk)
234 {
235         struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
236         struct rk3308_cru *cru = priv->cru;
237         u32 div, con, con_id;
238
239         switch (clk->id) {
240         case HCLK_SDMMC:
241         case SCLK_SDMMC:
242                 con_id = 39;
243                 break;
244         case HCLK_EMMC:
245         case SCLK_EMMC:
246         case SCLK_EMMC_SAMPLE:
247                 con_id = 41;
248                 break;
249         default:
250                 return -EINVAL;
251         }
252
253         con = readl(&cru->clksel_con[con_id]);
254         div = (con & EMMC_DIV_MASK) >> EMMC_DIV_SHIFT;
255
256         if ((con & EMMC_PLL_MASK) >> EMMC_PLL_SHIFT
257             == EMMC_SEL_24M)
258                 return DIV_TO_RATE(OSC_HZ, div) / 2;
259         else
260                 return DIV_TO_RATE(priv->vpll0_hz, div) / 2;
261 }
262
263 static ulong rk3308_mmc_set_clk(struct clk *clk, ulong set_rate)
264 {
265         struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
266         struct rk3308_cru *cru = priv->cru;
267         int src_clk_div;
268         u32 con_id;
269
270         switch (clk->id) {
271         case HCLK_SDMMC:
272         case SCLK_SDMMC:
273                 con_id = 39;
274                 break;
275         case HCLK_EMMC:
276         case SCLK_EMMC:
277                 con_id = 41;
278                 break;
279         default:
280                 return -EINVAL;
281         }
282         /* Select clk_sdmmc/emmc source from VPLL0 by default */
283         /* mmc clock defaulg div 2 internal, need provide double in cru */
284         src_clk_div = DIV_ROUND_UP(priv->vpll0_hz / 2, set_rate);
285
286         if (src_clk_div > 127) {
287                 /* use 24MHz source for 400KHz clock */
288                 src_clk_div = DIV_ROUND_UP(OSC_HZ / 2, set_rate);
289                 rk_clrsetreg(&cru->clksel_con[con_id],
290                              EMMC_PLL_MASK | EMMC_DIV_MASK | EMMC_CLK_SEL_MASK,
291                              EMMC_CLK_SEL_EMMC << EMMC_CLK_SEL_SHIFT |
292                              EMMC_SEL_24M << EMMC_PLL_SHIFT |
293                              (src_clk_div - 1) << EMMC_DIV_SHIFT);
294         } else {
295                 rk_clrsetreg(&cru->clksel_con[con_id],
296                              EMMC_PLL_MASK | EMMC_DIV_MASK | EMMC_CLK_SEL_MASK,
297                              EMMC_CLK_SEL_EMMC << EMMC_CLK_SEL_SHIFT |
298                              EMMC_SEL_VPLL0 << EMMC_PLL_SHIFT |
299                              (src_clk_div - 1) << EMMC_DIV_SHIFT);
300         }
301
302         return rk3308_mmc_get_clk(clk);
303 }
304
305 static ulong rk3308_saradc_get_clk(struct clk *clk)
306 {
307         struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
308         struct rk3308_cru *cru = priv->cru;
309         u32 div, con;
310
311         con = readl(&cru->clksel_con[34]);
312         div = con >> CLK_SARADC_DIV_CON_SHIFT & CLK_SARADC_DIV_CON_MASK;
313
314         return DIV_TO_RATE(OSC_HZ, div);
315 }
316
317 static ulong rk3308_saradc_set_clk(struct clk *clk, uint hz)
318 {
319         struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
320         struct rk3308_cru *cru = priv->cru;
321         int src_clk_div;
322
323         src_clk_div = DIV_ROUND_UP(OSC_HZ, hz);
324         assert(src_clk_div - 1 <= 2047);
325
326         rk_clrsetreg(&cru->clksel_con[34],
327                      CLK_SARADC_DIV_CON_MASK,
328                      (src_clk_div - 1) << CLK_SARADC_DIV_CON_SHIFT);
329
330         return rk3308_saradc_get_clk(clk);
331 }
332
333 static ulong rk3308_tsadc_get_clk(struct clk *clk)
334 {
335         struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
336         struct rk3308_cru *cru = priv->cru;
337         u32 div, con;
338
339         con = readl(&cru->clksel_con[33]);
340         div = con >> CLK_SARADC_DIV_CON_SHIFT & CLK_SARADC_DIV_CON_MASK;
341
342         return DIV_TO_RATE(OSC_HZ, div);
343 }
344
345 static ulong rk3308_tsadc_set_clk(struct clk *clk, uint hz)
346 {
347         struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
348         struct rk3308_cru *cru = priv->cru;
349         int src_clk_div;
350
351         src_clk_div = DIV_ROUND_UP(OSC_HZ, hz);
352         assert(src_clk_div - 1 <= 2047);
353
354         rk_clrsetreg(&cru->clksel_con[33],
355                      CLK_SARADC_DIV_CON_MASK,
356                      (src_clk_div - 1) << CLK_SARADC_DIV_CON_SHIFT);
357
358         return rk3308_tsadc_get_clk(clk);
359 }
360
361 static ulong rk3308_spi_get_clk(struct clk *clk)
362 {
363         struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
364         struct rk3308_cru *cru = priv->cru;
365         u32 div, con, con_id;
366
367         switch (clk->id) {
368         case SCLK_SPI0:
369                 con_id = 30;
370                 break;
371         case SCLK_SPI1:
372                 con_id = 31;
373                 break;
374         case SCLK_SPI2:
375                 con_id = 32;
376                 break;
377         default:
378                 printf("do not support this spi bus\n");
379                 return -EINVAL;
380         }
381
382         con = readl(&cru->clksel_con[con_id]);
383         div = con >> CLK_SPI_DIV_CON_SHIFT & CLK_SPI_DIV_CON_MASK;
384
385         return DIV_TO_RATE(priv->dpll_hz, div);
386 }
387
388 static ulong rk3308_spi_set_clk(struct clk *clk, uint hz)
389 {
390         struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
391         struct rk3308_cru *cru = priv->cru;
392         u32 src_clk_div, con_id;
393
394         src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz);
395         assert(src_clk_div - 1 <= 127);
396
397         switch (clk->id) {
398         case SCLK_SPI0:
399                 con_id = 30;
400                 break;
401         case SCLK_SPI1:
402                 con_id = 31;
403                 break;
404         case SCLK_SPI2:
405                 con_id = 32;
406                 break;
407         default:
408                 printf("do not support this spi bus\n");
409                 return -EINVAL;
410         }
411
412         rk_clrsetreg(&cru->clksel_con[con_id],
413                      CLK_SPI_PLL_SEL_MASK | CLK_SPI_DIV_CON_MASK,
414                      CLK_SPI_PLL_SEL_DPLL << CLK_SPI_PLL_SEL_SHIFT |
415                      (src_clk_div - 1) << CLK_SPI_DIV_CON_SHIFT);
416
417         return rk3308_spi_get_clk(clk);
418 }
419
420 static ulong rk3308_pwm_get_clk(struct clk *clk)
421 {
422         struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
423         struct rk3308_cru *cru = priv->cru;
424         u32 div, con;
425
426         con = readl(&cru->clksel_con[29]);
427         div = con >> CLK_PWM_DIV_CON_SHIFT & CLK_PWM_DIV_CON_MASK;
428
429         return DIV_TO_RATE(priv->dpll_hz, div);
430 }
431
432 static ulong rk3308_pwm_set_clk(struct clk *clk, uint hz)
433 {
434         struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
435         struct rk3308_cru *cru = priv->cru;
436         int src_clk_div;
437
438         src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz);
439         assert(src_clk_div - 1 <= 127);
440
441         rk_clrsetreg(&cru->clksel_con[29],
442                      CLK_PWM_PLL_SEL_MASK | CLK_PWM_DIV_CON_MASK,
443                      CLK_PWM_PLL_SEL_DPLL << CLK_PWM_PLL_SEL_SHIFT |
444                      (src_clk_div - 1) << CLK_PWM_DIV_CON_SHIFT);
445
446         return rk3308_pwm_get_clk(clk);
447 }
448
449 static ulong rk3308_vop_get_clk(struct clk *clk)
450 {
451         struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
452         struct rk3308_cru *cru = priv->cru;
453         u32 div, pll_sel, vol_sel, con, parent;
454
455         con = readl(&cru->clksel_con[8]);
456         vol_sel = (con & DCLK_VOP_SEL_MASK) >> DCLK_VOP_SEL_SHIFT;
457         pll_sel = (con & DCLK_VOP_PLL_SEL_MASK) >> DCLK_VOP_PLL_SEL_SHIFT;
458         div = con & DCLK_VOP_DIV_MASK;
459
460         if (vol_sel == DCLK_VOP_SEL_24M) {
461                 parent = OSC_HZ;
462         } else if (vol_sel == DCLK_VOP_SEL_DIVOUT) {
463                 switch (pll_sel) {
464                 case DCLK_VOP_PLL_SEL_DPLL:
465                         parent = priv->dpll_hz;
466                         break;
467                 case DCLK_VOP_PLL_SEL_VPLL0:
468                         parent = priv->vpll0_hz;
469                         break;
470                 case DCLK_VOP_PLL_SEL_VPLL1:
471                         parent = priv->vpll0_hz;
472                         break;
473                 default:
474                         printf("do not support this vop pll sel\n");
475                         return -EINVAL;
476                 }
477         } else {
478                 printf("do not support this vop sel\n");
479                 return -EINVAL;
480         }
481
482         return DIV_TO_RATE(parent, div);
483 }
484
485 static ulong rk3308_vop_set_clk(struct clk *clk, ulong hz)
486 {
487         struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
488         struct rk3308_cru *cru = priv->cru;
489         ulong pll_rate, now, best_rate = 0;
490         u32 i, div, best_div = 0, best_sel = 0;
491
492         for (i = 0; i <= DCLK_VOP_PLL_SEL_VPLL1; i++) {
493                 switch (i) {
494                 case DCLK_VOP_PLL_SEL_DPLL:
495                         pll_rate = priv->dpll_hz;
496                         break;
497                 case DCLK_VOP_PLL_SEL_VPLL0:
498                         pll_rate = priv->vpll0_hz;
499                         break;
500                 case DCLK_VOP_PLL_SEL_VPLL1:
501                         pll_rate = priv->vpll1_hz;
502                         break;
503                 default:
504                         printf("do not support this vop pll sel\n");
505                         return -EINVAL;
506                 }
507
508                 div = DIV_ROUND_UP(pll_rate, hz);
509                 if (div > 255)
510                         continue;
511                 now = pll_rate / div;
512                 if (abs(hz - now) < abs(hz - best_rate)) {
513                         best_rate = now;
514                         best_div = div;
515                         best_sel = i;
516                 }
517                 debug("pll_rate=%lu, best_rate=%lu, best_div=%u, best_sel=%u\n",
518                       pll_rate, best_rate, best_div, best_sel);
519         }
520
521         if (best_rate != hz && hz == OSC_HZ) {
522                 rk_clrsetreg(&cru->clksel_con[8],
523                              DCLK_VOP_SEL_MASK,
524                              DCLK_VOP_SEL_24M << DCLK_VOP_SEL_SHIFT);
525         } else if (best_rate) {
526                 rk_clrsetreg(&cru->clksel_con[8],
527                              DCLK_VOP_SEL_MASK | DCLK_VOP_PLL_SEL_MASK |
528                              DCLK_VOP_DIV_MASK,
529                              DCLK_VOP_SEL_DIVOUT << DCLK_VOP_SEL_SHIFT |
530                              best_sel << DCLK_VOP_PLL_SEL_SHIFT |
531                              (best_div - 1) << DCLK_VOP_DIV_SHIFT);
532         } else {
533                 printf("do not support this vop freq\n");
534                 return -EINVAL;
535         }
536
537         return rk3308_vop_get_clk(clk);
538 }
539
540 static ulong rk3308_bus_get_clk(struct rk3308_clk_priv *priv, ulong clk_id)
541 {
542         struct rk3308_cru *cru = priv->cru;
543         u32 div, con, parent = priv->dpll_hz;
544
545         switch (clk_id) {
546         case ACLK_BUS:
547                 con = readl(&cru->clksel_con[5]);
548                 div = (con & BUS_ACLK_DIV_MASK) >> BUS_ACLK_DIV_SHIFT;
549                 break;
550         case HCLK_BUS:
551                 con = readl(&cru->clksel_con[6]);
552                 div = (con & BUS_HCLK_DIV_MASK) >> BUS_HCLK_DIV_SHIFT;
553                 break;
554         case PCLK_BUS:
555         case PCLK_WDT:
556                 con = readl(&cru->clksel_con[6]);
557                 div = (con & BUS_PCLK_DIV_MASK) >> BUS_PCLK_DIV_SHIFT;
558                 break;
559         default:
560                 return -ENOENT;
561         }
562
563         return DIV_TO_RATE(parent, div);
564 }
565
566 static ulong rk3308_bus_set_clk(struct rk3308_clk_priv *priv, ulong clk_id,
567                                 ulong hz)
568 {
569         struct rk3308_cru *cru = priv->cru;
570         int src_clk_div;
571
572         src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz);
573         assert(src_clk_div - 1 <= 31);
574
575         /*
576          * select dpll as pd_bus bus clock source and
577          * set up dependent divisors for PCLK/HCLK and ACLK clocks.
578          */
579         switch (clk_id) {
580         case ACLK_BUS:
581                 rk_clrsetreg(&cru->clksel_con[5],
582                              BUS_PLL_SEL_MASK | BUS_ACLK_DIV_MASK,
583                              BUS_PLL_SEL_DPLL << BUS_PLL_SEL_SHIFT |
584                              (src_clk_div - 1) << BUS_ACLK_DIV_SHIFT);
585                 break;
586         case HCLK_BUS:
587                 rk_clrsetreg(&cru->clksel_con[6],
588                              BUS_HCLK_DIV_MASK,
589                              (src_clk_div - 1) << BUS_HCLK_DIV_SHIFT);
590                 break;
591         case PCLK_BUS:
592                 rk_clrsetreg(&cru->clksel_con[6],
593                              BUS_PCLK_DIV_MASK,
594                              (src_clk_div - 1) << BUS_PCLK_DIV_SHIFT);
595                 break;
596         default:
597                 printf("do not support this bus freq\n");
598                 return -EINVAL;
599         }
600
601         return rk3308_bus_get_clk(priv, clk_id);
602 }
603
604 static ulong rk3308_peri_get_clk(struct rk3308_clk_priv *priv, ulong clk_id)
605 {
606         struct rk3308_cru *cru = priv->cru;
607         u32 div, con, parent = priv->dpll_hz;
608
609         switch (clk_id) {
610         case ACLK_PERI:
611                 con = readl(&cru->clksel_con[36]);
612                 div = (con & PERI_ACLK_DIV_MASK) >> PERI_ACLK_DIV_SHIFT;
613                 break;
614         case HCLK_PERI:
615                 con = readl(&cru->clksel_con[37]);
616                 div = (con & PERI_HCLK_DIV_MASK) >> PERI_HCLK_DIV_SHIFT;
617                 break;
618         case PCLK_PERI:
619                 con = readl(&cru->clksel_con[37]);
620                 div = (con & PERI_PCLK_DIV_MASK) >> PERI_PCLK_DIV_SHIFT;
621                 break;
622         default:
623                 return -ENOENT;
624         }
625
626         return DIV_TO_RATE(parent, div);
627 }
628
629 static ulong rk3308_peri_set_clk(struct rk3308_clk_priv *priv, ulong clk_id,
630                                  ulong hz)
631 {
632         struct rk3308_cru *cru = priv->cru;
633         int src_clk_div;
634
635         src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz);
636         assert(src_clk_div - 1 <= 31);
637
638         /*
639          * select dpll as pd_peri bus clock source and
640          * set up dependent divisors for PCLK/HCLK and ACLK clocks.
641          */
642         switch (clk_id) {
643         case ACLK_PERI:
644                 rk_clrsetreg(&cru->clksel_con[36],
645                              PERI_PLL_SEL_MASK | PERI_ACLK_DIV_MASK,
646                              PERI_PLL_DPLL << PERI_PLL_SEL_SHIFT |
647                              (src_clk_div - 1) << PERI_ACLK_DIV_SHIFT);
648                 break;
649         case HCLK_PERI:
650                 rk_clrsetreg(&cru->clksel_con[37],
651                              PERI_HCLK_DIV_MASK,
652                              (src_clk_div - 1) << PERI_HCLK_DIV_SHIFT);
653                 break;
654         case PCLK_PERI:
655                 rk_clrsetreg(&cru->clksel_con[37],
656                              PERI_PCLK_DIV_MASK,
657                              (src_clk_div - 1) << PERI_PCLK_DIV_SHIFT);
658                 break;
659         default:
660                 printf("do not support this peri freq\n");
661                 return -EINVAL;
662         }
663
664         return rk3308_peri_get_clk(priv, clk_id);
665 }
666
667 static ulong rk3308_audio_get_clk(struct rk3308_clk_priv *priv, ulong clk_id)
668 {
669         struct rk3308_cru *cru = priv->cru;
670         u32 div, con, parent = priv->vpll0_hz;
671
672         switch (clk_id) {
673         case HCLK_AUDIO:
674                 con = readl(&cru->clksel_con[45]);
675                 div = (con & AUDIO_HCLK_DIV_MASK) >> AUDIO_HCLK_DIV_SHIFT;
676                 break;
677         case PCLK_AUDIO:
678                 con = readl(&cru->clksel_con[45]);
679                 div = (con & AUDIO_PCLK_DIV_MASK) >> AUDIO_PCLK_DIV_SHIFT;
680                 break;
681         default:
682                 return -ENOENT;
683         }
684
685         return DIV_TO_RATE(parent, div);
686 }
687
688 static ulong rk3308_audio_set_clk(struct rk3308_clk_priv *priv, ulong clk_id,
689                                   ulong hz)
690 {
691         struct rk3308_cru *cru = priv->cru;
692         int src_clk_div;
693
694         src_clk_div = DIV_ROUND_UP(priv->vpll0_hz, hz);
695         assert(src_clk_div - 1 <= 31);
696
697         /*
698          * select vpll0 as audio bus clock source and
699          * set up dependent divisors for HCLK and PCLK clocks.
700          */
701         switch (clk_id) {
702         case HCLK_AUDIO:
703                 rk_clrsetreg(&cru->clksel_con[45],
704                              AUDIO_PLL_SEL_MASK | AUDIO_HCLK_DIV_MASK,
705                              AUDIO_PLL_VPLL0 << AUDIO_PLL_SEL_SHIFT |
706                              (src_clk_div - 1) << AUDIO_HCLK_DIV_SHIFT);
707                 break;
708         case PCLK_AUDIO:
709                 rk_clrsetreg(&cru->clksel_con[45],
710                              AUDIO_PLL_SEL_MASK | AUDIO_PCLK_DIV_MASK,
711                              AUDIO_PLL_VPLL0 << AUDIO_PLL_SEL_SHIFT |
712                              (src_clk_div - 1) << AUDIO_PCLK_DIV_SHIFT);
713                 break;
714         default:
715                 printf("do not support this audio freq\n");
716                 return -EINVAL;
717         }
718
719         return rk3308_peri_get_clk(priv, clk_id);
720 }
721
722 static ulong rk3308_crypto_get_clk(struct rk3308_clk_priv *priv, ulong clk_id)
723 {
724         struct rk3308_cru *cru = priv->cru;
725         u32 div, con, parent;
726
727         switch (clk_id) {
728         case SCLK_CRYPTO:
729                 con = readl(&cru->clksel_con[7]);
730                 div = (con & CRYPTO_DIV_MASK) >> CRYPTO_DIV_SHIFT;
731                 parent = priv->vpll0_hz;
732                 break;
733         case SCLK_CRYPTO_APK:
734                 con = readl(&cru->clksel_con[7]);
735                 div = (con & CRYPTO_APK_DIV_MASK) >> CRYPTO_APK_DIV_SHIFT;
736                 parent = priv->vpll0_hz;
737                 break;
738         default:
739                 return -ENOENT;
740         }
741
742         return DIV_TO_RATE(parent, div);
743 }
744
745 static ulong rk3308_crypto_set_clk(struct rk3308_clk_priv *priv, ulong clk_id,
746                                    ulong hz)
747 {
748         struct rk3308_cru *cru = priv->cru;
749         int src_clk_div;
750
751         src_clk_div = DIV_ROUND_UP(priv->vpll0_hz, hz);
752         assert(src_clk_div - 1 <= 31);
753
754         /*
755          * select gpll as crypto clock source and
756          * set up dependent divisors for crypto clocks.
757          */
758         switch (clk_id) {
759         case SCLK_CRYPTO:
760                 rk_clrsetreg(&cru->clksel_con[7],
761                              CRYPTO_PLL_SEL_MASK | CRYPTO_DIV_MASK,
762                              CRYPTO_PLL_SEL_VPLL0 << CRYPTO_PLL_SEL_SHIFT |
763                              (src_clk_div - 1) << CRYPTO_DIV_SHIFT);
764                 break;
765         case SCLK_CRYPTO_APK:
766                 rk_clrsetreg(&cru->clksel_con[7],
767                              CRYPTO_APK_PLL_SEL_MASK | CRYPTO_APK_DIV_MASK,
768                              CRYPTO_PLL_SEL_VPLL0 << CRYPTO_APK_SEL_SHIFT |
769                              (src_clk_div - 1) << CRYPTO_APK_DIV_SHIFT);
770                 break;
771         default:
772                 printf("do not support this peri freq\n");
773                 return -EINVAL;
774         }
775
776         return rk3308_crypto_get_clk(priv, clk_id);
777 }
778
779 static ulong rk3308_clk_get_rate(struct clk *clk)
780 {
781         struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
782         ulong rate = 0;
783
784         debug("%s id:%ld\n", __func__, clk->id);
785
786         switch (clk->id) {
787         case PLL_APLL:
788         case ARMCLK:
789                 rate = rockchip_pll_get_rate(&rk3308_pll_clks[APLL],
790                                              priv->cru, APLL);
791                 break;
792         case PLL_DPLL:
793                 rate = rockchip_pll_get_rate(&rk3308_pll_clks[DPLL],
794                                              priv->cru, DPLL);
795                 break;
796         case PLL_VPLL0:
797                 rate = rockchip_pll_get_rate(&rk3308_pll_clks[VPLL0],
798                                              priv->cru, VPLL0);
799                 break;
800         case PLL_VPLL1:
801                 rate = rockchip_pll_get_rate(&rk3308_pll_clks[VPLL1],
802                                              priv->cru, VPLL1);
803                 break;
804         case HCLK_SDMMC:
805         case HCLK_EMMC:
806         case SCLK_SDMMC:
807         case SCLK_EMMC:
808         case SCLK_EMMC_SAMPLE:
809                 rate = rk3308_mmc_get_clk(clk);
810                 break;
811         case SCLK_I2C0:
812         case SCLK_I2C1:
813         case SCLK_I2C2:
814         case SCLK_I2C3:
815                 rate = rk3308_i2c_get_clk(clk);
816                 break;
817         case SCLK_SARADC:
818                 rate = rk3308_saradc_get_clk(clk);
819                 break;
820         case SCLK_TSADC:
821                 rate = rk3308_tsadc_get_clk(clk);
822                 break;
823         case SCLK_SPI0:
824         case SCLK_SPI1:
825                 rate = rk3308_spi_get_clk(clk);
826                 break;
827         case SCLK_PWM0:
828                 rate = rk3308_pwm_get_clk(clk);
829                 break;
830         case DCLK_VOP:
831                 rate = rk3308_vop_get_clk(clk);
832                 break;
833         case ACLK_BUS:
834         case HCLK_BUS:
835         case PCLK_BUS:
836         case PCLK_WDT:
837                 rate = rk3308_bus_get_clk(priv, clk->id);
838                 break;
839         case ACLK_PERI:
840         case HCLK_PERI:
841         case PCLK_PERI:
842                 rate = rk3308_peri_get_clk(priv, clk->id);
843                 break;
844         case HCLK_AUDIO:
845         case PCLK_AUDIO:
846                 rate = rk3308_audio_get_clk(priv, clk->id);
847                 break;
848         case SCLK_CRYPTO:
849         case SCLK_CRYPTO_APK:
850                 rate = rk3308_crypto_get_clk(priv, clk->id);
851                 break;
852         default:
853                 return -ENOENT;
854         }
855
856         return rate;
857 }
858
859 static ulong rk3308_clk_set_rate(struct clk *clk, ulong rate)
860 {
861         struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
862         ulong ret = 0;
863
864         debug("%s %ld %ld\n", __func__, clk->id, rate);
865
866         switch (clk->id) {
867         case PLL_DPLL:
868                 ret = rockchip_pll_set_rate(&rk3308_pll_clks[DPLL], priv->cru,
869                                             DPLL, rate);
870                 priv->dpll_hz = rockchip_pll_get_rate(&rk3308_pll_clks[DPLL],
871                                                       priv->cru, DPLL);
872                 break;
873         case ARMCLK:
874                 if (priv->armclk_hz)
875                         rk3308_armclk_set_clk(priv, rate);
876                 priv->armclk_hz = rate;
877                 break;
878         case HCLK_SDMMC:
879         case HCLK_EMMC:
880         case SCLK_SDMMC:
881         case SCLK_EMMC:
882                 ret = rk3308_mmc_set_clk(clk, rate);
883                 break;
884         case SCLK_I2C0:
885         case SCLK_I2C1:
886         case SCLK_I2C2:
887         case SCLK_I2C3:
888                 ret = rk3308_i2c_set_clk(clk, rate);
889                 break;
890         case SCLK_MAC:
891                 ret = rk3308_mac_set_clk(clk, rate);
892                 break;
893         case SCLK_MAC_RMII:
894                 ret = rk3308_mac_set_speed_clk(clk, rate);
895                 break;
896         case SCLK_SARADC:
897                 ret = rk3308_saradc_set_clk(clk, rate);
898                 break;
899         case SCLK_TSADC:
900                 ret = rk3308_tsadc_set_clk(clk, rate);
901                 break;
902         case SCLK_SPI0:
903         case SCLK_SPI1:
904                 ret = rk3308_spi_set_clk(clk, rate);
905                 break;
906         case SCLK_PWM0:
907                 ret = rk3308_pwm_set_clk(clk, rate);
908                 break;
909         case DCLK_VOP:
910                 ret = rk3308_vop_set_clk(clk, rate);
911                 break;
912         case ACLK_BUS:
913         case HCLK_BUS:
914         case PCLK_BUS:
915                 rate = rk3308_bus_set_clk(priv, clk->id, rate);
916                 break;
917         case ACLK_PERI:
918         case HCLK_PERI:
919         case PCLK_PERI:
920                 rate = rk3308_peri_set_clk(priv, clk->id, rate);
921                 break;
922         case HCLK_AUDIO:
923         case PCLK_AUDIO:
924                 rate = rk3308_audio_set_clk(priv, clk->id, rate);
925                 break;
926         case SCLK_CRYPTO:
927         case SCLK_CRYPTO_APK:
928                 ret = rk3308_crypto_set_clk(priv, clk->id, rate);
929                 break;
930         default:
931                 return -ENOENT;
932         }
933
934         return ret;
935 }
936
937 #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
938 static int __maybe_unused rk3308_mac_set_parent(struct clk *clk, struct clk *parent)
939 {
940         struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
941
942         /*
943          * If the requested parent is in the same clock-controller and
944          * the id is SCLK_MAC_SRC, switch to the internal clock.
945          */
946         if (parent->id == SCLK_MAC_SRC) {
947                 debug("%s: switching RMII to SCLK_MAC\n", __func__);
948                 rk_clrreg(&priv->cru->clksel_con[43], BIT(14));
949         } else {
950                 debug("%s: switching RMII to CLKIN\n", __func__);
951                 rk_setreg(&priv->cru->clksel_con[43], BIT(14));
952         }
953
954         return 0;
955 }
956
957 static int __maybe_unused rk3308_clk_set_parent(struct clk *clk, struct clk *parent)
958 {
959         switch (clk->id) {
960         case SCLK_MAC:
961                 return rk3308_mac_set_parent(clk, parent);
962         default:
963                 break;
964         }
965
966         debug("%s: unsupported clk %ld\n", __func__, clk->id);
967         return -ENOENT;
968 }
969 #endif
970
971 static struct clk_ops rk3308_clk_ops = {
972         .get_rate = rk3308_clk_get_rate,
973         .set_rate = rk3308_clk_set_rate,
974 #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
975         .set_parent = rk3308_clk_set_parent,
976 #endif
977 };
978
979 static void rk3308_clk_init(struct udevice *dev)
980 {
981         struct rk3308_clk_priv *priv = dev_get_priv(dev);
982         int ret;
983
984         if (rockchip_pll_get_rate(&rk3308_pll_clks[APLL],
985                                   priv->cru, APLL) != APLL_HZ) {
986                 ret = rk3308_armclk_set_clk(priv, APLL_HZ);
987                 if (ret < 0)
988                         printf("%s failed to set armclk rate\n", __func__);
989         }
990
991         rk3308_clk_get_pll_rate(priv);
992
993         rk3308_bus_set_clk(priv, ACLK_BUS, BUS_ACLK_HZ);
994         rk3308_bus_set_clk(priv, HCLK_BUS, BUS_HCLK_HZ);
995         rk3308_bus_set_clk(priv, PCLK_BUS, BUS_PCLK_HZ);
996
997         rk3308_peri_set_clk(priv, ACLK_PERI, PERI_ACLK_HZ);
998         rk3308_peri_set_clk(priv, HCLK_PERI, PERI_HCLK_HZ);
999         rk3308_peri_set_clk(priv, PCLK_PERI, PERI_PCLK_HZ);
1000
1001         rk3308_audio_set_clk(priv, HCLK_AUDIO, AUDIO_HCLK_HZ);
1002         rk3308_audio_set_clk(priv, PCLK_AUDIO, AUDIO_PCLK_HZ);
1003 }
1004
1005 static int rk3308_clk_probe(struct udevice *dev)
1006 {
1007         int ret;
1008
1009         rk3308_clk_init(dev);
1010
1011         /* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */
1012         ret = clk_set_defaults(dev, 1);
1013         if (ret)
1014                 debug("%s clk_set_defaults failed %d\n", __func__, ret);
1015
1016         return ret;
1017 }
1018
1019 static int rk3308_clk_ofdata_to_platdata(struct udevice *dev)
1020 {
1021         struct rk3308_clk_priv *priv = dev_get_priv(dev);
1022
1023         priv->cru = dev_read_addr_ptr(dev);
1024
1025         return 0;
1026 }
1027
1028 static int rk3308_clk_bind(struct udevice *dev)
1029 {
1030         int ret;
1031         struct udevice *sys_child;
1032         struct sysreset_reg *priv;
1033
1034         /* The reset driver does not have a device node, so bind it here */
1035         ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
1036                                  &sys_child);
1037         if (ret) {
1038                 debug("Warning: No sysreset driver: ret=%d\n", ret);
1039         } else {
1040                 priv = malloc(sizeof(struct sysreset_reg));
1041                 priv->glb_srst_fst_value = offsetof(struct rk3308_cru,
1042                                                     glb_srst_fst);
1043                 priv->glb_srst_snd_value = offsetof(struct rk3308_cru,
1044                                                     glb_srst_snd);
1045                 sys_child->priv = priv;
1046         }
1047
1048 #if CONFIG_IS_ENABLED(RESET_ROCKCHIP)
1049         ret = offsetof(struct rk3308_cru, softrst_con[0]);
1050         ret = rockchip_reset_bind(dev, ret, 12);
1051         if (ret)
1052                 debug("Warning: software reset driver bind faile\n");
1053 #endif
1054
1055         return 0;
1056 }
1057
1058 static const struct udevice_id rk3308_clk_ids[] = {
1059         { .compatible = "rockchip,rk3308-cru" },
1060         { }
1061 };
1062
1063 U_BOOT_DRIVER(rockchip_rk3308_cru) = {
1064         .name           = "rockchip_rk3308_cru",
1065         .id             = UCLASS_CLK,
1066         .of_match       = rk3308_clk_ids,
1067         .priv_auto_alloc_size = sizeof(struct rk3308_clk_priv),
1068         .ofdata_to_platdata = rk3308_clk_ofdata_to_platdata,
1069         .ops            = &rk3308_clk_ops,
1070         .bind           = rk3308_clk_bind,
1071         .probe          = rk3308_clk_probe,
1072 };