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