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