blob: fdc5347d0a71752cf9529ba8af9e1ce255eabada [file] [log] [blame]
Simon Glass421358c2015-08-30 16:55:31 -06001/*
2 * (C) Copyright 2015 Google, Inc
3 *
4 * SPDX-License-Identifier: GPL-2.0
5 */
6
7#include <common.h>
8#include <clk.h>
9#include <dm.h>
10#include <errno.h>
11#include <syscon.h>
12#include <asm/io.h>
13#include <asm/arch/clock.h>
14#include <asm/arch/cru_rk3288.h>
15#include <asm/arch/grf_rk3288.h>
16#include <asm/arch/hardware.h>
Simon Glass8d32f4b2016-01-21 19:43:38 -070017#include <dt-bindings/clock/rk3288-cru.h>
Simon Glass344f3662016-01-21 19:43:41 -070018#include <dm/device-internal.h>
Simon Glass421358c2015-08-30 16:55:31 -060019#include <dm/lists.h>
Simon Glass344f3662016-01-21 19:43:41 -070020#include <dm/uclass-internal.h>
Simon Glass421358c2015-08-30 16:55:31 -060021
22DECLARE_GLOBAL_DATA_PTR;
23
24struct rk3288_clk_plat {
25 enum rk_clk_id clk_id;
26};
27
28struct rk3288_clk_priv {
29 struct rk3288_grf *grf;
30 struct rk3288_cru *cru;
31 ulong rate;
32};
33
34struct pll_div {
35 u32 nr;
36 u32 nf;
37 u32 no;
38};
39
40enum {
41 VCO_MAX_HZ = 2200U * 1000000,
42 VCO_MIN_HZ = 440 * 1000000,
43 OUTPUT_MAX_HZ = 2200U * 1000000,
44 OUTPUT_MIN_HZ = 27500000,
45 FREF_MAX_HZ = 2200U * 1000000,
46 FREF_MIN_HZ = 269 * 1000000,
47};
48
49enum {
50 /* PLL CON0 */
51 PLL_OD_MASK = 0x0f,
52
53 /* PLL CON1 */
54 PLL_NF_MASK = 0x1fff,
55
56 /* PLL CON2 */
57 PLL_BWADJ_MASK = 0x0fff,
58
59 /* PLL CON3 */
60 PLL_RESET_SHIFT = 5,
61
62 /* CLKSEL1: pd bus clk pll sel: codec or general */
63 PD_BUS_SEL_PLL_MASK = 15,
64 PD_BUS_SEL_CPLL = 0,
65 PD_BUS_SEL_GPLL,
66
67 /* pd bus pclk div: pclk = pd_bus_aclk /(div + 1) */
68 PD_BUS_PCLK_DIV_SHIFT = 12,
69 PD_BUS_PCLK_DIV_MASK = 7,
70
71 /* pd bus hclk div: aclk_bus: hclk_bus = 1:1 or 2:1 or 4:1 */
72 PD_BUS_HCLK_DIV_SHIFT = 8,
73 PD_BUS_HCLK_DIV_MASK = 3,
74
75 /* pd bus aclk div: pd_bus_aclk = pd_bus_src_clk /(div0 * div1) */
76 PD_BUS_ACLK_DIV0_SHIFT = 3,
77 PD_BUS_ACLK_DIV0_MASK = 0x1f,
78 PD_BUS_ACLK_DIV1_SHIFT = 0,
79 PD_BUS_ACLK_DIV1_MASK = 0x7,
80
81 /*
82 * CLKSEL10
83 * peripheral bus pclk div:
84 * aclk_bus: pclk_bus = 1:1 or 2:1 or 4:1 or 8:1
85 */
86 PERI_PCLK_DIV_SHIFT = 12,
87 PERI_PCLK_DIV_MASK = 7,
88
89 /* peripheral bus hclk div: aclk_bus: hclk_bus = 1:1 or 2:1 or 4:1 */
90 PERI_HCLK_DIV_SHIFT = 8,
91 PERI_HCLK_DIV_MASK = 3,
92
93 /*
94 * peripheral bus aclk div:
95 * aclk_periph = periph_clk_src / (peri_aclk_div_con + 1)
96 */
97 PERI_ACLK_DIV_SHIFT = 0,
98 PERI_ACLK_DIV_MASK = 0x1f,
99
100 /* CLKSEL37 */
101 DPLL_MODE_MASK = 0x3,
102 DPLL_MODE_SHIFT = 4,
103 DPLL_MODE_SLOW = 0,
104 DPLL_MODE_NORM,
105
106 CPLL_MODE_MASK = 3,
107 CPLL_MODE_SHIFT = 8,
108 CPLL_MODE_SLOW = 0,
109 CPLL_MODE_NORM,
110
111 GPLL_MODE_MASK = 3,
112 GPLL_MODE_SHIFT = 12,
113 GPLL_MODE_SLOW = 0,
114 GPLL_MODE_NORM,
115
116 NPLL_MODE_MASK = 3,
117 NPLL_MODE_SHIFT = 14,
118 NPLL_MODE_SLOW = 0,
119 NPLL_MODE_NORM,
120
121 SOCSTS_DPLL_LOCK = 1 << 5,
122 SOCSTS_APLL_LOCK = 1 << 6,
123 SOCSTS_CPLL_LOCK = 1 << 7,
124 SOCSTS_GPLL_LOCK = 1 << 8,
125 SOCSTS_NPLL_LOCK = 1 << 9,
126};
127
128#define RATE_TO_DIV(input_rate, output_rate) \
129 ((input_rate) / (output_rate) - 1);
130
131#define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1))
132
133#define PLL_DIVISORS(hz, _nr, _no) {\
134 .nr = _nr, .nf = (u32)((u64)hz * _nr * _no / OSC_HZ), .no = _no};\
135 _Static_assert(((u64)hz * _nr * _no / OSC_HZ) * OSC_HZ /\
136 (_nr * _no) == hz, #hz "Hz cannot be hit with PLL "\
137 "divisors on line " __stringify(__LINE__));
138
139/* Keep divisors as low as possible to reduce jitter and power usage */
140static const struct pll_div apll_init_cfg = PLL_DIVISORS(APLL_HZ, 1, 1);
141static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 2, 2);
142static const struct pll_div cpll_init_cfg = PLL_DIVISORS(CPLL_HZ, 1, 2);
143
Simon Glass344f3662016-01-21 19:43:41 -0700144int rkclk_get_clk(enum rk_clk_id clk_id, struct udevice **devp)
145{
146 struct udevice *dev;
147
148 for (uclass_find_first_device(UCLASS_CLK, &dev);
149 dev;
150 uclass_find_next_device(&dev)) {
151 struct rk3288_clk_plat *plat = dev_get_platdata(dev);
152
153 if (plat->clk_id == clk_id) {
154 *devp = dev;
155 return device_probe(dev);
156 }
157 }
158
159 return -ENODEV;
160}
161
Simon Glass421358c2015-08-30 16:55:31 -0600162static int rkclk_set_pll(struct rk3288_cru *cru, enum rk_clk_id clk_id,
163 const struct pll_div *div)
164{
165 int pll_id = rk_pll_id(clk_id);
166 struct rk3288_pll *pll = &cru->pll[pll_id];
167 /* All PLLs have same VCO and output frequency range restrictions. */
168 uint vco_hz = OSC_HZ / 1000 * div->nf / div->nr * 1000;
169 uint output_hz = vco_hz / div->no;
170
171 debug("PLL at %p: nf=%d, nr=%d, no=%d, vco=%u Hz, output=%u Hz\n",
172 pll, div->nf, div->nr, div->no, vco_hz, output_hz);
173 assert(vco_hz >= VCO_MIN_HZ && vco_hz <= VCO_MAX_HZ &&
174 output_hz >= OUTPUT_MIN_HZ && output_hz <= OUTPUT_MAX_HZ &&
175 (div->no == 1 || !(div->no % 2)));
176
177 /* enter rest */
178 rk_setreg(&pll->con3, 1 << PLL_RESET_SHIFT);
179
180 rk_clrsetreg(&pll->con0,
181 CLKR_MASK << CLKR_SHIFT | PLL_OD_MASK,
182 ((div->nr - 1) << CLKR_SHIFT) | (div->no - 1));
183 rk_clrsetreg(&pll->con1, CLKF_MASK, div->nf - 1);
184 rk_clrsetreg(&pll->con2, PLL_BWADJ_MASK, (div->nf >> 1) - 1);
185
186 udelay(10);
187
188 /* return form rest */
189 rk_clrreg(&pll->con3, 1 << PLL_RESET_SHIFT);
190
191 return 0;
192}
193
194static inline unsigned int log2(unsigned int value)
195{
196 return fls(value) - 1;
197}
198
199static int rkclk_configure_ddr(struct rk3288_cru *cru, struct rk3288_grf *grf,
200 unsigned int hz)
201{
202 static const struct pll_div dpll_cfg[] = {
203 {.nf = 25, .nr = 2, .no = 1},
204 {.nf = 400, .nr = 9, .no = 2},
205 {.nf = 500, .nr = 9, .no = 2},
206 {.nf = 100, .nr = 3, .no = 1},
207 };
208 int cfg;
209
210 debug("%s: cru=%p, grf=%p, hz=%u\n", __func__, cru, grf, hz);
211 switch (hz) {
212 case 300000000:
213 cfg = 0;
214 break;
215 case 533000000: /* actually 533.3P MHz */
216 cfg = 1;
217 break;
218 case 666000000: /* actually 666.6P MHz */
219 cfg = 2;
220 break;
221 case 800000000:
222 cfg = 3;
223 break;
224 default:
225 debug("Unsupported SDRAM frequency, add to clock.c!");
226 return -EINVAL;
227 }
228
229 /* pll enter slow-mode */
230 rk_clrsetreg(&cru->cru_mode_con, DPLL_MODE_MASK << DPLL_MODE_SHIFT,
231 DPLL_MODE_SLOW << DPLL_MODE_SHIFT);
232
233 rkclk_set_pll(cru, CLK_DDR, &dpll_cfg[cfg]);
234
235 /* wait for pll lock */
236 while (!(readl(&grf->soc_status[1]) & SOCSTS_DPLL_LOCK))
237 udelay(1);
238
239 /* PLL enter normal-mode */
240 rk_clrsetreg(&cru->cru_mode_con, DPLL_MODE_MASK << DPLL_MODE_SHIFT,
241 DPLL_MODE_NORM << DPLL_MODE_SHIFT);
242
243 return 0;
244}
245
246#ifdef CONFIG_SPL_BUILD
247static void rkclk_init(struct rk3288_cru *cru, struct rk3288_grf *grf)
248{
249 u32 aclk_div;
250 u32 hclk_div;
251 u32 pclk_div;
252
253 /* pll enter slow-mode */
254 rk_clrsetreg(&cru->cru_mode_con,
255 GPLL_MODE_MASK << GPLL_MODE_SHIFT |
256 CPLL_MODE_MASK << CPLL_MODE_SHIFT,
257 GPLL_MODE_SLOW << GPLL_MODE_SHIFT |
258 CPLL_MODE_SLOW << CPLL_MODE_SHIFT);
259
260 /* init pll */
261 rkclk_set_pll(cru, CLK_GENERAL, &gpll_init_cfg);
262 rkclk_set_pll(cru, CLK_CODEC, &cpll_init_cfg);
263
264 /* waiting for pll lock */
265 while ((readl(&grf->soc_status[1]) &
266 (SOCSTS_CPLL_LOCK | SOCSTS_GPLL_LOCK)) !=
267 (SOCSTS_CPLL_LOCK | SOCSTS_GPLL_LOCK))
268 udelay(1);
269
270 /*
271 * pd_bus clock pll source selection and
272 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
273 */
274 aclk_div = GPLL_HZ / PD_BUS_ACLK_HZ - 1;
275 assert((aclk_div + 1) * PD_BUS_ACLK_HZ == GPLL_HZ && aclk_div < 0x1f);
276 hclk_div = PD_BUS_ACLK_HZ / PD_BUS_HCLK_HZ - 1;
277 assert((hclk_div + 1) * PD_BUS_HCLK_HZ ==
278 PD_BUS_ACLK_HZ && (hclk_div < 0x4) && (hclk_div != 0x2));
279
280 pclk_div = PD_BUS_ACLK_HZ / PD_BUS_PCLK_HZ - 1;
281 assert((pclk_div + 1) * PD_BUS_PCLK_HZ ==
282 PD_BUS_ACLK_HZ && pclk_div < 0x7);
283
284 rk_clrsetreg(&cru->cru_clksel_con[1],
285 PD_BUS_PCLK_DIV_MASK << PD_BUS_PCLK_DIV_SHIFT |
286 PD_BUS_HCLK_DIV_MASK << PD_BUS_HCLK_DIV_SHIFT |
287 PD_BUS_ACLK_DIV0_MASK << PD_BUS_ACLK_DIV0_SHIFT |
288 PD_BUS_ACLK_DIV1_MASK << PD_BUS_ACLK_DIV1_SHIFT,
289 pclk_div << PD_BUS_PCLK_DIV_SHIFT |
290 hclk_div << PD_BUS_HCLK_DIV_SHIFT |
291 aclk_div << PD_BUS_ACLK_DIV0_SHIFT |
292 0 << 0);
293
294 /*
295 * peri clock pll source selection and
296 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
297 */
298 aclk_div = GPLL_HZ / PERI_ACLK_HZ - 1;
299 assert((aclk_div + 1) * PERI_ACLK_HZ == GPLL_HZ && aclk_div < 0x1f);
300
301 hclk_div = log2(PERI_ACLK_HZ / PERI_HCLK_HZ);
302 assert((1 << hclk_div) * PERI_HCLK_HZ ==
303 PERI_ACLK_HZ && (hclk_div < 0x4));
304
305 pclk_div = log2(PERI_ACLK_HZ / PERI_PCLK_HZ);
306 assert((1 << pclk_div) * PERI_PCLK_HZ ==
307 PERI_ACLK_HZ && (pclk_div < 0x4));
308
309 rk_clrsetreg(&cru->cru_clksel_con[10],
310 PERI_PCLK_DIV_MASK << PERI_PCLK_DIV_SHIFT |
311 PERI_HCLK_DIV_MASK << PERI_HCLK_DIV_SHIFT |
312 PERI_ACLK_DIV_MASK << PERI_ACLK_DIV_SHIFT,
313 pclk_div << PERI_PCLK_DIV_SHIFT |
314 hclk_div << PERI_HCLK_DIV_SHIFT |
315 aclk_div << PERI_ACLK_DIV_SHIFT);
316
317 /* PLL enter normal-mode */
318 rk_clrsetreg(&cru->cru_mode_con,
319 GPLL_MODE_MASK << GPLL_MODE_SHIFT |
320 CPLL_MODE_MASK << CPLL_MODE_SHIFT,
321 GPLL_MODE_NORM << GPLL_MODE_SHIFT |
322 GPLL_MODE_NORM << CPLL_MODE_SHIFT);
323}
324#endif
325
326/* Get pll rate by id */
327static uint32_t rkclk_pll_get_rate(struct rk3288_cru *cru,
328 enum rk_clk_id clk_id)
329{
330 uint32_t nr, no, nf;
331 uint32_t con;
332 int pll_id = rk_pll_id(clk_id);
333 struct rk3288_pll *pll = &cru->pll[pll_id];
334 static u8 clk_shift[CLK_COUNT] = {
335 0xff, APLL_WORK_SHIFT, DPLL_WORK_SHIFT, CPLL_WORK_SHIFT,
336 GPLL_WORK_SHIFT, NPLL_WORK_SHIFT
337 };
338 uint shift;
339
340 con = readl(&cru->cru_mode_con);
341 shift = clk_shift[clk_id];
342 switch ((con >> shift) & APLL_WORK_MASK) {
343 case APLL_WORK_SLOW:
344 return OSC_HZ;
345 case APLL_WORK_NORMAL:
346 /* normal mode */
347 con = readl(&pll->con0);
348 no = ((con >> CLKOD_SHIFT) & CLKOD_MASK) + 1;
349 nr = ((con >> CLKR_SHIFT) & CLKR_MASK) + 1;
350 con = readl(&pll->con1);
351 nf = ((con >> CLKF_SHIFT) & CLKF_MASK) + 1;
352
353 return (24 * nf / (nr * no)) * 1000000;
354 case APLL_WORK_DEEP:
355 default:
356 return 32768;
357 }
358}
359
360static ulong rk3288_clk_get_rate(struct udevice *dev)
361{
362 struct rk3288_clk_plat *plat = dev_get_platdata(dev);
363 struct rk3288_clk_priv *priv = dev_get_priv(dev);
364
365 debug("%s\n", dev->name);
366 return rkclk_pll_get_rate(priv->cru, plat->clk_id);
367}
368
369static ulong rk3288_clk_set_rate(struct udevice *dev, ulong rate)
370{
371 struct rk3288_clk_plat *plat = dev_get_platdata(dev);
372 struct rk3288_clk_priv *priv = dev_get_priv(dev);
373
374 debug("%s\n", dev->name);
375 switch (plat->clk_id) {
376 case CLK_DDR:
377 rkclk_configure_ddr(priv->cru, priv->grf, rate);
378 break;
379 default:
380 return -ENOENT;
381 }
382
383 return 0;
384}
385
Simon Glassafe0cb02016-01-21 19:43:39 -0700386static ulong rockchip_mmc_get_clk(struct rk3288_cru *cru, uint gclk_rate,
Simon Glass8d32f4b2016-01-21 19:43:38 -0700387 int periph)
Simon Glass421358c2015-08-30 16:55:31 -0600388{
389 uint src_rate;
390 uint div, mux;
391 u32 con;
392
393 switch (periph) {
Simon Glass8d32f4b2016-01-21 19:43:38 -0700394 case HCLK_EMMC:
Simon Glass421358c2015-08-30 16:55:31 -0600395 con = readl(&cru->cru_clksel_con[12]);
396 mux = (con >> EMMC_PLL_SHIFT) & EMMC_PLL_MASK;
397 div = (con >> EMMC_DIV_SHIFT) & EMMC_DIV_MASK;
398 break;
Simon Glass8d32f4b2016-01-21 19:43:38 -0700399 case HCLK_SDMMC:
400 con = readl(&cru->cru_clksel_con[11]);
Simon Glass421358c2015-08-30 16:55:31 -0600401 mux = (con >> MMC0_PLL_SHIFT) & MMC0_PLL_MASK;
402 div = (con >> MMC0_DIV_SHIFT) & MMC0_DIV_MASK;
403 break;
Simon Glass8d32f4b2016-01-21 19:43:38 -0700404 case HCLK_SDIO0:
Simon Glass421358c2015-08-30 16:55:31 -0600405 con = readl(&cru->cru_clksel_con[12]);
406 mux = (con >> SDIO0_PLL_SHIFT) & SDIO0_PLL_MASK;
407 div = (con >> SDIO0_DIV_SHIFT) & SDIO0_DIV_MASK;
408 break;
409 default:
410 return -EINVAL;
411 }
412
Simon Glassafe0cb02016-01-21 19:43:39 -0700413 src_rate = mux == EMMC_PLL_SELECT_24MHZ ? OSC_HZ : gclk_rate;
Simon Glass421358c2015-08-30 16:55:31 -0600414 return DIV_TO_RATE(src_rate, div);
415}
416
Simon Glassafe0cb02016-01-21 19:43:39 -0700417static ulong rockchip_mmc_set_clk(struct rk3288_cru *cru, uint gclk_rate,
Simon Glass8d32f4b2016-01-21 19:43:38 -0700418 int periph, uint freq)
Simon Glass421358c2015-08-30 16:55:31 -0600419{
420 int src_clk_div;
421 int mux;
422
Simon Glassafe0cb02016-01-21 19:43:39 -0700423 debug("%s: gclk_rate=%u\n", __func__, gclk_rate);
424 src_clk_div = RATE_TO_DIV(gclk_rate, freq);
Simon Glass421358c2015-08-30 16:55:31 -0600425
426 if (src_clk_div > 0x3f) {
427 src_clk_div = RATE_TO_DIV(OSC_HZ, freq);
428 mux = EMMC_PLL_SELECT_24MHZ;
429 assert((int)EMMC_PLL_SELECT_24MHZ ==
430 (int)MMC0_PLL_SELECT_24MHZ);
431 } else {
432 mux = EMMC_PLL_SELECT_GENERAL;
433 assert((int)EMMC_PLL_SELECT_GENERAL ==
434 (int)MMC0_PLL_SELECT_GENERAL);
435 }
436 switch (periph) {
Simon Glass8d32f4b2016-01-21 19:43:38 -0700437 case HCLK_EMMC:
Simon Glass421358c2015-08-30 16:55:31 -0600438 rk_clrsetreg(&cru->cru_clksel_con[12],
439 EMMC_PLL_MASK << EMMC_PLL_SHIFT |
440 EMMC_DIV_MASK << EMMC_DIV_SHIFT,
441 mux << EMMC_PLL_SHIFT |
442 (src_clk_div - 1) << EMMC_DIV_SHIFT);
443 break;
Simon Glass8d32f4b2016-01-21 19:43:38 -0700444 case HCLK_SDMMC:
Simon Glass421358c2015-08-30 16:55:31 -0600445 rk_clrsetreg(&cru->cru_clksel_con[11],
446 MMC0_PLL_MASK << MMC0_PLL_SHIFT |
447 MMC0_DIV_MASK << MMC0_DIV_SHIFT,
448 mux << MMC0_PLL_SHIFT |
449 (src_clk_div - 1) << MMC0_DIV_SHIFT);
450 break;
Simon Glass8d32f4b2016-01-21 19:43:38 -0700451 case HCLK_SDIO0:
Simon Glass421358c2015-08-30 16:55:31 -0600452 rk_clrsetreg(&cru->cru_clksel_con[12],
453 SDIO0_PLL_MASK << SDIO0_PLL_SHIFT |
454 SDIO0_DIV_MASK << SDIO0_DIV_SHIFT,
455 mux << SDIO0_PLL_SHIFT |
456 (src_clk_div - 1) << SDIO0_DIV_SHIFT);
457 break;
458 default:
459 return -EINVAL;
460 }
461
Simon Glassafe0cb02016-01-21 19:43:39 -0700462 return rockchip_mmc_get_clk(cru, gclk_rate, periph);
Simon Glass421358c2015-08-30 16:55:31 -0600463}
464
Simon Glassafe0cb02016-01-21 19:43:39 -0700465static ulong rockchip_spi_get_clk(struct rk3288_cru *cru, uint gclk_rate,
Simon Glass8d32f4b2016-01-21 19:43:38 -0700466 int periph)
Simon Glass421358c2015-08-30 16:55:31 -0600467{
468 uint div, mux;
469 u32 con;
470
471 switch (periph) {
Simon Glass8d32f4b2016-01-21 19:43:38 -0700472 case SCLK_SPI0:
Simon Glass421358c2015-08-30 16:55:31 -0600473 con = readl(&cru->cru_clksel_con[25]);
474 mux = (con >> SPI0_PLL_SHIFT) & SPI0_PLL_MASK;
475 div = (con >> SPI0_DIV_SHIFT) & SPI0_DIV_MASK;
476 break;
Simon Glass8d32f4b2016-01-21 19:43:38 -0700477 case SCLK_SPI1:
Simon Glass421358c2015-08-30 16:55:31 -0600478 con = readl(&cru->cru_clksel_con[25]);
479 mux = (con >> SPI1_PLL_SHIFT) & SPI1_PLL_MASK;
480 div = (con >> SPI1_DIV_SHIFT) & SPI1_DIV_MASK;
481 break;
Simon Glass8d32f4b2016-01-21 19:43:38 -0700482 case SCLK_SPI2:
Simon Glass421358c2015-08-30 16:55:31 -0600483 con = readl(&cru->cru_clksel_con[39]);
484 mux = (con >> SPI2_PLL_SHIFT) & SPI2_PLL_MASK;
485 div = (con >> SPI2_DIV_SHIFT) & SPI2_DIV_MASK;
486 break;
487 default:
488 return -EINVAL;
489 }
490 assert(mux == SPI0_PLL_SELECT_GENERAL);
491
Simon Glassafe0cb02016-01-21 19:43:39 -0700492 return DIV_TO_RATE(gclk_rate, div);
Simon Glass421358c2015-08-30 16:55:31 -0600493}
494
Simon Glassafe0cb02016-01-21 19:43:39 -0700495static ulong rockchip_spi_set_clk(struct rk3288_cru *cru, uint gclk_rate,
Simon Glass8d32f4b2016-01-21 19:43:38 -0700496 int periph, uint freq)
Simon Glass421358c2015-08-30 16:55:31 -0600497{
498 int src_clk_div;
499
Simon Glassafe0cb02016-01-21 19:43:39 -0700500 debug("%s: clk_general_rate=%u\n", __func__, gclk_rate);
501 src_clk_div = RATE_TO_DIV(gclk_rate, freq);
Simon Glass421358c2015-08-30 16:55:31 -0600502 switch (periph) {
Simon Glass8d32f4b2016-01-21 19:43:38 -0700503 case SCLK_SPI0:
Simon Glass421358c2015-08-30 16:55:31 -0600504 rk_clrsetreg(&cru->cru_clksel_con[25],
505 SPI0_PLL_MASK << SPI0_PLL_SHIFT |
506 SPI0_DIV_MASK << SPI0_DIV_SHIFT,
507 SPI0_PLL_SELECT_GENERAL << SPI0_PLL_SHIFT |
508 src_clk_div << SPI0_DIV_SHIFT);
509 break;
Simon Glass8d32f4b2016-01-21 19:43:38 -0700510 case SCLK_SPI1:
Simon Glass421358c2015-08-30 16:55:31 -0600511 rk_clrsetreg(&cru->cru_clksel_con[25],
512 SPI1_PLL_MASK << SPI1_PLL_SHIFT |
513 SPI1_DIV_MASK << SPI1_DIV_SHIFT,
514 SPI1_PLL_SELECT_GENERAL << SPI1_PLL_SHIFT |
515 src_clk_div << SPI1_DIV_SHIFT);
516 break;
Simon Glass8d32f4b2016-01-21 19:43:38 -0700517 case SCLK_SPI2:
Simon Glass421358c2015-08-30 16:55:31 -0600518 rk_clrsetreg(&cru->cru_clksel_con[39],
519 SPI2_PLL_MASK << SPI2_PLL_SHIFT |
520 SPI2_DIV_MASK << SPI2_DIV_SHIFT,
521 SPI2_PLL_SELECT_GENERAL << SPI2_PLL_SHIFT |
522 src_clk_div << SPI2_DIV_SHIFT);
523 break;
524 default:
525 return -EINVAL;
526 }
527
Simon Glassafe0cb02016-01-21 19:43:39 -0700528 return rockchip_spi_get_clk(cru, gclk_rate, periph);
Simon Glass421358c2015-08-30 16:55:31 -0600529}
530
Simon Glass398ced12016-01-21 19:43:40 -0700531static ulong rk3288_get_periph_rate(struct udevice *dev, int periph)
532{
533 struct rk3288_clk_priv *priv = dev_get_priv(dev);
534 struct udevice *gclk;
535 ulong new_rate, gclk_rate;
536 int ret;
537
Simon Glass344f3662016-01-21 19:43:41 -0700538 ret = rkclk_get_clk(CLK_GENERAL, &gclk);
Simon Glass398ced12016-01-21 19:43:40 -0700539 if (ret)
540 return ret;
541 gclk_rate = clk_get_rate(gclk);
542 switch (periph) {
543 case HCLK_EMMC:
544 case HCLK_SDIO0:
545 case HCLK_SDIO1:
546 new_rate = rockchip_mmc_get_clk(priv->cru, gclk_rate, periph);
547 break;
548 case SCLK_SPI0:
549 case SCLK_SPI1:
550 case SCLK_SPI2:
551 new_rate = rockchip_spi_get_clk(priv->cru, gclk_rate, periph);
552 break;
553 case PCLK_I2C0:
554 case PCLK_I2C1:
555 case PCLK_I2C2:
556 case PCLK_I2C3:
557 case PCLK_I2C4:
558 case PCLK_I2C5:
559 return gclk_rate;
560 default:
561 return -ENOENT;
562 }
563
564 return new_rate;
565}
566
Masahiro Yamadaecf20f62016-01-13 13:16:10 +0900567static ulong rk3288_set_periph_rate(struct udevice *dev, int periph, ulong rate)
Simon Glass421358c2015-08-30 16:55:31 -0600568{
569 struct rk3288_clk_priv *priv = dev_get_priv(dev);
Simon Glass8d32f4b2016-01-21 19:43:38 -0700570 struct udevice *gclk;
571 ulong new_rate, gclk_rate;
572 int ret;
Simon Glass421358c2015-08-30 16:55:31 -0600573
Simon Glass344f3662016-01-21 19:43:41 -0700574 ret = rkclk_get_clk(CLK_GENERAL, &gclk);
Simon Glass8d32f4b2016-01-21 19:43:38 -0700575 if (ret)
576 return ret;
577 gclk_rate = clk_get_rate(gclk);
Simon Glass421358c2015-08-30 16:55:31 -0600578 switch (periph) {
Simon Glass8d32f4b2016-01-21 19:43:38 -0700579 case HCLK_EMMC:
580 case HCLK_SDMMC:
581 case HCLK_SDIO0:
582 new_rate = rockchip_mmc_set_clk(priv->cru, gclk_rate, periph,
583 rate);
Simon Glass421358c2015-08-30 16:55:31 -0600584 break;
Simon Glass8d32f4b2016-01-21 19:43:38 -0700585 case SCLK_SPI0:
586 case SCLK_SPI1:
587 case SCLK_SPI2:
588 new_rate = rockchip_spi_set_clk(priv->cru, gclk_rate, periph,
589 rate);
Simon Glass421358c2015-08-30 16:55:31 -0600590 break;
591 default:
592 return -ENOENT;
593 }
594
595 return new_rate;
596}
597
598static struct clk_ops rk3288_clk_ops = {
599 .get_rate = rk3288_clk_get_rate,
600 .set_rate = rk3288_clk_set_rate,
601 .set_periph_rate = rk3288_set_periph_rate,
Simon Glass398ced12016-01-21 19:43:40 -0700602 .get_periph_rate = rk3288_get_periph_rate,
Simon Glass421358c2015-08-30 16:55:31 -0600603};
604
605static int rk3288_clk_probe(struct udevice *dev)
606{
607 struct rk3288_clk_plat *plat = dev_get_platdata(dev);
608 struct rk3288_clk_priv *priv = dev_get_priv(dev);
609
610 if (plat->clk_id != CLK_OSC) {
611 struct rk3288_clk_priv *parent_priv = dev_get_priv(dev->parent);
612
613 priv->cru = parent_priv->cru;
614 priv->grf = parent_priv->grf;
615 return 0;
616 }
617 priv->cru = (struct rk3288_cru *)dev_get_addr(dev);
618 priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
619#ifdef CONFIG_SPL_BUILD
620 rkclk_init(priv->cru, priv->grf);
621#endif
622
623 return 0;
624}
625
626static const char *const clk_name[CLK_COUNT] = {
627 "osc",
628 "apll",
629 "dpll",
630 "cpll",
631 "gpll",
632 "mpll",
633};
634
635static int rk3288_clk_bind(struct udevice *dev)
636{
637 struct rk3288_clk_plat *plat = dev_get_platdata(dev);
638 int pll, ret;
639
640 /* We only need to set up the root clock */
641 if (dev->of_offset == -1) {
642 plat->clk_id = CLK_OSC;
643 return 0;
644 }
645
646 /* Create devices for P main clocks */
647 for (pll = 1; pll < CLK_COUNT; pll++) {
648 struct udevice *child;
649 struct rk3288_clk_plat *cplat;
650
651 debug("%s %s\n", __func__, clk_name[pll]);
652 ret = device_bind_driver(dev, "clk_rk3288", clk_name[pll],
653 &child);
654 if (ret)
655 return ret;
656 cplat = dev_get_platdata(child);
657 cplat->clk_id = pll;
658 }
659
660 /* The reset driver does not have a device node, so bind it here */
661 ret = device_bind_driver(gd->dm_root, "rk3288_reset", "reset", &dev);
662 if (ret)
663 debug("Warning: No RK3288 reset driver: ret=%d\n", ret);
664
665 return 0;
666}
667
668static const struct udevice_id rk3288_clk_ids[] = {
669 { .compatible = "rockchip,rk3288-cru" },
670 { }
671};
672
673U_BOOT_DRIVER(clk_rk3288) = {
674 .name = "clk_rk3288",
675 .id = UCLASS_CLK,
676 .of_match = rk3288_clk_ids,
677 .priv_auto_alloc_size = sizeof(struct rk3288_clk_priv),
678 .platdata_auto_alloc_size = sizeof(struct rk3288_clk_plat),
679 .ops = &rk3288_clk_ops,
680 .bind = rk3288_clk_bind,
681 .probe = rk3288_clk_probe,
682};