blob: 5a8f175e4b062d33811011fb98c9f913361fe4b6 [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 Glass410d45c2016-01-21 19:44:05 -0700162void *rockchip_get_cru(void)
163{
164 struct rk3288_clk_priv *priv;
165 struct udevice *dev;
166 int ret;
167
168 ret = rkclk_get_clk(CLK_GENERAL, &dev);
169 if (ret)
170 return ERR_PTR(ret);
171 priv = dev_get_priv(dev);
172 return priv->cru;
173}
174
Simon Glass421358c2015-08-30 16:55:31 -0600175static int rkclk_set_pll(struct rk3288_cru *cru, enum rk_clk_id clk_id,
176 const struct pll_div *div)
177{
178 int pll_id = rk_pll_id(clk_id);
179 struct rk3288_pll *pll = &cru->pll[pll_id];
180 /* All PLLs have same VCO and output frequency range restrictions. */
181 uint vco_hz = OSC_HZ / 1000 * div->nf / div->nr * 1000;
182 uint output_hz = vco_hz / div->no;
183
184 debug("PLL at %p: nf=%d, nr=%d, no=%d, vco=%u Hz, output=%u Hz\n",
185 pll, div->nf, div->nr, div->no, vco_hz, output_hz);
186 assert(vco_hz >= VCO_MIN_HZ && vco_hz <= VCO_MAX_HZ &&
187 output_hz >= OUTPUT_MIN_HZ && output_hz <= OUTPUT_MAX_HZ &&
188 (div->no == 1 || !(div->no % 2)));
189
190 /* enter rest */
191 rk_setreg(&pll->con3, 1 << PLL_RESET_SHIFT);
192
193 rk_clrsetreg(&pll->con0,
194 CLKR_MASK << CLKR_SHIFT | PLL_OD_MASK,
195 ((div->nr - 1) << CLKR_SHIFT) | (div->no - 1));
196 rk_clrsetreg(&pll->con1, CLKF_MASK, div->nf - 1);
197 rk_clrsetreg(&pll->con2, PLL_BWADJ_MASK, (div->nf >> 1) - 1);
198
199 udelay(10);
200
201 /* return form rest */
202 rk_clrreg(&pll->con3, 1 << PLL_RESET_SHIFT);
203
204 return 0;
205}
206
207static inline unsigned int log2(unsigned int value)
208{
209 return fls(value) - 1;
210}
211
212static int rkclk_configure_ddr(struct rk3288_cru *cru, struct rk3288_grf *grf,
213 unsigned int hz)
214{
215 static const struct pll_div dpll_cfg[] = {
216 {.nf = 25, .nr = 2, .no = 1},
217 {.nf = 400, .nr = 9, .no = 2},
218 {.nf = 500, .nr = 9, .no = 2},
219 {.nf = 100, .nr = 3, .no = 1},
220 };
221 int cfg;
222
223 debug("%s: cru=%p, grf=%p, hz=%u\n", __func__, cru, grf, hz);
224 switch (hz) {
225 case 300000000:
226 cfg = 0;
227 break;
228 case 533000000: /* actually 533.3P MHz */
229 cfg = 1;
230 break;
231 case 666000000: /* actually 666.6P MHz */
232 cfg = 2;
233 break;
234 case 800000000:
235 cfg = 3;
236 break;
237 default:
238 debug("Unsupported SDRAM frequency, add to clock.c!");
239 return -EINVAL;
240 }
241
242 /* pll enter slow-mode */
243 rk_clrsetreg(&cru->cru_mode_con, DPLL_MODE_MASK << DPLL_MODE_SHIFT,
244 DPLL_MODE_SLOW << DPLL_MODE_SHIFT);
245
246 rkclk_set_pll(cru, CLK_DDR, &dpll_cfg[cfg]);
247
248 /* wait for pll lock */
249 while (!(readl(&grf->soc_status[1]) & SOCSTS_DPLL_LOCK))
250 udelay(1);
251
252 /* PLL enter normal-mode */
253 rk_clrsetreg(&cru->cru_mode_con, DPLL_MODE_MASK << DPLL_MODE_SHIFT,
254 DPLL_MODE_NORM << DPLL_MODE_SHIFT);
255
256 return 0;
257}
258
259#ifdef CONFIG_SPL_BUILD
260static void rkclk_init(struct rk3288_cru *cru, struct rk3288_grf *grf)
261{
262 u32 aclk_div;
263 u32 hclk_div;
264 u32 pclk_div;
265
266 /* pll enter slow-mode */
267 rk_clrsetreg(&cru->cru_mode_con,
268 GPLL_MODE_MASK << GPLL_MODE_SHIFT |
269 CPLL_MODE_MASK << CPLL_MODE_SHIFT,
270 GPLL_MODE_SLOW << GPLL_MODE_SHIFT |
271 CPLL_MODE_SLOW << CPLL_MODE_SHIFT);
272
273 /* init pll */
274 rkclk_set_pll(cru, CLK_GENERAL, &gpll_init_cfg);
275 rkclk_set_pll(cru, CLK_CODEC, &cpll_init_cfg);
276
277 /* waiting for pll lock */
278 while ((readl(&grf->soc_status[1]) &
279 (SOCSTS_CPLL_LOCK | SOCSTS_GPLL_LOCK)) !=
280 (SOCSTS_CPLL_LOCK | SOCSTS_GPLL_LOCK))
281 udelay(1);
282
283 /*
284 * pd_bus clock pll source selection and
285 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
286 */
287 aclk_div = GPLL_HZ / PD_BUS_ACLK_HZ - 1;
288 assert((aclk_div + 1) * PD_BUS_ACLK_HZ == GPLL_HZ && aclk_div < 0x1f);
289 hclk_div = PD_BUS_ACLK_HZ / PD_BUS_HCLK_HZ - 1;
290 assert((hclk_div + 1) * PD_BUS_HCLK_HZ ==
291 PD_BUS_ACLK_HZ && (hclk_div < 0x4) && (hclk_div != 0x2));
292
293 pclk_div = PD_BUS_ACLK_HZ / PD_BUS_PCLK_HZ - 1;
294 assert((pclk_div + 1) * PD_BUS_PCLK_HZ ==
295 PD_BUS_ACLK_HZ && pclk_div < 0x7);
296
297 rk_clrsetreg(&cru->cru_clksel_con[1],
298 PD_BUS_PCLK_DIV_MASK << PD_BUS_PCLK_DIV_SHIFT |
299 PD_BUS_HCLK_DIV_MASK << PD_BUS_HCLK_DIV_SHIFT |
300 PD_BUS_ACLK_DIV0_MASK << PD_BUS_ACLK_DIV0_SHIFT |
301 PD_BUS_ACLK_DIV1_MASK << PD_BUS_ACLK_DIV1_SHIFT,
302 pclk_div << PD_BUS_PCLK_DIV_SHIFT |
303 hclk_div << PD_BUS_HCLK_DIV_SHIFT |
304 aclk_div << PD_BUS_ACLK_DIV0_SHIFT |
305 0 << 0);
306
307 /*
308 * peri clock pll source selection and
309 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
310 */
311 aclk_div = GPLL_HZ / PERI_ACLK_HZ - 1;
312 assert((aclk_div + 1) * PERI_ACLK_HZ == GPLL_HZ && aclk_div < 0x1f);
313
314 hclk_div = log2(PERI_ACLK_HZ / PERI_HCLK_HZ);
315 assert((1 << hclk_div) * PERI_HCLK_HZ ==
316 PERI_ACLK_HZ && (hclk_div < 0x4));
317
318 pclk_div = log2(PERI_ACLK_HZ / PERI_PCLK_HZ);
319 assert((1 << pclk_div) * PERI_PCLK_HZ ==
320 PERI_ACLK_HZ && (pclk_div < 0x4));
321
322 rk_clrsetreg(&cru->cru_clksel_con[10],
323 PERI_PCLK_DIV_MASK << PERI_PCLK_DIV_SHIFT |
324 PERI_HCLK_DIV_MASK << PERI_HCLK_DIV_SHIFT |
325 PERI_ACLK_DIV_MASK << PERI_ACLK_DIV_SHIFT,
326 pclk_div << PERI_PCLK_DIV_SHIFT |
327 hclk_div << PERI_HCLK_DIV_SHIFT |
328 aclk_div << PERI_ACLK_DIV_SHIFT);
329
330 /* PLL enter normal-mode */
331 rk_clrsetreg(&cru->cru_mode_con,
332 GPLL_MODE_MASK << GPLL_MODE_SHIFT |
333 CPLL_MODE_MASK << CPLL_MODE_SHIFT,
334 GPLL_MODE_NORM << GPLL_MODE_SHIFT |
335 GPLL_MODE_NORM << CPLL_MODE_SHIFT);
336}
337#endif
338
339/* Get pll rate by id */
340static uint32_t rkclk_pll_get_rate(struct rk3288_cru *cru,
341 enum rk_clk_id clk_id)
342{
343 uint32_t nr, no, nf;
344 uint32_t con;
345 int pll_id = rk_pll_id(clk_id);
346 struct rk3288_pll *pll = &cru->pll[pll_id];
347 static u8 clk_shift[CLK_COUNT] = {
348 0xff, APLL_WORK_SHIFT, DPLL_WORK_SHIFT, CPLL_WORK_SHIFT,
349 GPLL_WORK_SHIFT, NPLL_WORK_SHIFT
350 };
351 uint shift;
352
353 con = readl(&cru->cru_mode_con);
354 shift = clk_shift[clk_id];
355 switch ((con >> shift) & APLL_WORK_MASK) {
356 case APLL_WORK_SLOW:
357 return OSC_HZ;
358 case APLL_WORK_NORMAL:
359 /* normal mode */
360 con = readl(&pll->con0);
361 no = ((con >> CLKOD_SHIFT) & CLKOD_MASK) + 1;
362 nr = ((con >> CLKR_SHIFT) & CLKR_MASK) + 1;
363 con = readl(&pll->con1);
364 nf = ((con >> CLKF_SHIFT) & CLKF_MASK) + 1;
365
366 return (24 * nf / (nr * no)) * 1000000;
367 case APLL_WORK_DEEP:
368 default:
369 return 32768;
370 }
371}
372
373static ulong rk3288_clk_get_rate(struct udevice *dev)
374{
375 struct rk3288_clk_plat *plat = dev_get_platdata(dev);
376 struct rk3288_clk_priv *priv = dev_get_priv(dev);
377
378 debug("%s\n", dev->name);
379 return rkclk_pll_get_rate(priv->cru, plat->clk_id);
380}
381
382static ulong rk3288_clk_set_rate(struct udevice *dev, ulong rate)
383{
384 struct rk3288_clk_plat *plat = dev_get_platdata(dev);
385 struct rk3288_clk_priv *priv = dev_get_priv(dev);
386
387 debug("%s\n", dev->name);
388 switch (plat->clk_id) {
389 case CLK_DDR:
390 rkclk_configure_ddr(priv->cru, priv->grf, rate);
391 break;
392 default:
393 return -ENOENT;
394 }
395
396 return 0;
397}
398
Simon Glassafe0cb02016-01-21 19:43:39 -0700399static ulong rockchip_mmc_get_clk(struct rk3288_cru *cru, uint gclk_rate,
Simon Glass8d32f4b2016-01-21 19:43:38 -0700400 int periph)
Simon Glass421358c2015-08-30 16:55:31 -0600401{
402 uint src_rate;
403 uint div, mux;
404 u32 con;
405
406 switch (periph) {
Simon Glass8d32f4b2016-01-21 19:43:38 -0700407 case HCLK_EMMC:
Simon Glass421358c2015-08-30 16:55:31 -0600408 con = readl(&cru->cru_clksel_con[12]);
409 mux = (con >> EMMC_PLL_SHIFT) & EMMC_PLL_MASK;
410 div = (con >> EMMC_DIV_SHIFT) & EMMC_DIV_MASK;
411 break;
Simon Glass8d32f4b2016-01-21 19:43:38 -0700412 case HCLK_SDMMC:
413 con = readl(&cru->cru_clksel_con[11]);
Simon Glass421358c2015-08-30 16:55:31 -0600414 mux = (con >> MMC0_PLL_SHIFT) & MMC0_PLL_MASK;
415 div = (con >> MMC0_DIV_SHIFT) & MMC0_DIV_MASK;
416 break;
Simon Glass8d32f4b2016-01-21 19:43:38 -0700417 case HCLK_SDIO0:
Simon Glass421358c2015-08-30 16:55:31 -0600418 con = readl(&cru->cru_clksel_con[12]);
419 mux = (con >> SDIO0_PLL_SHIFT) & SDIO0_PLL_MASK;
420 div = (con >> SDIO0_DIV_SHIFT) & SDIO0_DIV_MASK;
421 break;
422 default:
423 return -EINVAL;
424 }
425
Simon Glassafe0cb02016-01-21 19:43:39 -0700426 src_rate = mux == EMMC_PLL_SELECT_24MHZ ? OSC_HZ : gclk_rate;
Simon Glass421358c2015-08-30 16:55:31 -0600427 return DIV_TO_RATE(src_rate, div);
428}
429
Simon Glassafe0cb02016-01-21 19:43:39 -0700430static ulong rockchip_mmc_set_clk(struct rk3288_cru *cru, uint gclk_rate,
Simon Glass8d32f4b2016-01-21 19:43:38 -0700431 int periph, uint freq)
Simon Glass421358c2015-08-30 16:55:31 -0600432{
433 int src_clk_div;
434 int mux;
435
Simon Glassafe0cb02016-01-21 19:43:39 -0700436 debug("%s: gclk_rate=%u\n", __func__, gclk_rate);
437 src_clk_div = RATE_TO_DIV(gclk_rate, freq);
Simon Glass421358c2015-08-30 16:55:31 -0600438
439 if (src_clk_div > 0x3f) {
440 src_clk_div = RATE_TO_DIV(OSC_HZ, freq);
441 mux = EMMC_PLL_SELECT_24MHZ;
442 assert((int)EMMC_PLL_SELECT_24MHZ ==
443 (int)MMC0_PLL_SELECT_24MHZ);
444 } else {
445 mux = EMMC_PLL_SELECT_GENERAL;
446 assert((int)EMMC_PLL_SELECT_GENERAL ==
447 (int)MMC0_PLL_SELECT_GENERAL);
448 }
449 switch (periph) {
Simon Glass8d32f4b2016-01-21 19:43:38 -0700450 case HCLK_EMMC:
Simon Glass421358c2015-08-30 16:55:31 -0600451 rk_clrsetreg(&cru->cru_clksel_con[12],
452 EMMC_PLL_MASK << EMMC_PLL_SHIFT |
453 EMMC_DIV_MASK << EMMC_DIV_SHIFT,
454 mux << EMMC_PLL_SHIFT |
455 (src_clk_div - 1) << EMMC_DIV_SHIFT);
456 break;
Simon Glass8d32f4b2016-01-21 19:43:38 -0700457 case HCLK_SDMMC:
Simon Glass421358c2015-08-30 16:55:31 -0600458 rk_clrsetreg(&cru->cru_clksel_con[11],
459 MMC0_PLL_MASK << MMC0_PLL_SHIFT |
460 MMC0_DIV_MASK << MMC0_DIV_SHIFT,
461 mux << MMC0_PLL_SHIFT |
462 (src_clk_div - 1) << MMC0_DIV_SHIFT);
463 break;
Simon Glass8d32f4b2016-01-21 19:43:38 -0700464 case HCLK_SDIO0:
Simon Glass421358c2015-08-30 16:55:31 -0600465 rk_clrsetreg(&cru->cru_clksel_con[12],
466 SDIO0_PLL_MASK << SDIO0_PLL_SHIFT |
467 SDIO0_DIV_MASK << SDIO0_DIV_SHIFT,
468 mux << SDIO0_PLL_SHIFT |
469 (src_clk_div - 1) << SDIO0_DIV_SHIFT);
470 break;
471 default:
472 return -EINVAL;
473 }
474
Simon Glassafe0cb02016-01-21 19:43:39 -0700475 return rockchip_mmc_get_clk(cru, gclk_rate, periph);
Simon Glass421358c2015-08-30 16:55:31 -0600476}
477
Simon Glassafe0cb02016-01-21 19:43:39 -0700478static ulong rockchip_spi_get_clk(struct rk3288_cru *cru, uint gclk_rate,
Simon Glass8d32f4b2016-01-21 19:43:38 -0700479 int periph)
Simon Glass421358c2015-08-30 16:55:31 -0600480{
481 uint div, mux;
482 u32 con;
483
484 switch (periph) {
Simon Glass8d32f4b2016-01-21 19:43:38 -0700485 case SCLK_SPI0:
Simon Glass421358c2015-08-30 16:55:31 -0600486 con = readl(&cru->cru_clksel_con[25]);
487 mux = (con >> SPI0_PLL_SHIFT) & SPI0_PLL_MASK;
488 div = (con >> SPI0_DIV_SHIFT) & SPI0_DIV_MASK;
489 break;
Simon Glass8d32f4b2016-01-21 19:43:38 -0700490 case SCLK_SPI1:
Simon Glass421358c2015-08-30 16:55:31 -0600491 con = readl(&cru->cru_clksel_con[25]);
492 mux = (con >> SPI1_PLL_SHIFT) & SPI1_PLL_MASK;
493 div = (con >> SPI1_DIV_SHIFT) & SPI1_DIV_MASK;
494 break;
Simon Glass8d32f4b2016-01-21 19:43:38 -0700495 case SCLK_SPI2:
Simon Glass421358c2015-08-30 16:55:31 -0600496 con = readl(&cru->cru_clksel_con[39]);
497 mux = (con >> SPI2_PLL_SHIFT) & SPI2_PLL_MASK;
498 div = (con >> SPI2_DIV_SHIFT) & SPI2_DIV_MASK;
499 break;
500 default:
501 return -EINVAL;
502 }
503 assert(mux == SPI0_PLL_SELECT_GENERAL);
504
Simon Glassafe0cb02016-01-21 19:43:39 -0700505 return DIV_TO_RATE(gclk_rate, div);
Simon Glass421358c2015-08-30 16:55:31 -0600506}
507
Simon Glassafe0cb02016-01-21 19:43:39 -0700508static ulong rockchip_spi_set_clk(struct rk3288_cru *cru, uint gclk_rate,
Simon Glass8d32f4b2016-01-21 19:43:38 -0700509 int periph, uint freq)
Simon Glass421358c2015-08-30 16:55:31 -0600510{
511 int src_clk_div;
512
Simon Glassafe0cb02016-01-21 19:43:39 -0700513 debug("%s: clk_general_rate=%u\n", __func__, gclk_rate);
514 src_clk_div = RATE_TO_DIV(gclk_rate, freq);
Simon Glass421358c2015-08-30 16:55:31 -0600515 switch (periph) {
Simon Glass8d32f4b2016-01-21 19:43:38 -0700516 case SCLK_SPI0:
Simon Glass421358c2015-08-30 16:55:31 -0600517 rk_clrsetreg(&cru->cru_clksel_con[25],
518 SPI0_PLL_MASK << SPI0_PLL_SHIFT |
519 SPI0_DIV_MASK << SPI0_DIV_SHIFT,
520 SPI0_PLL_SELECT_GENERAL << SPI0_PLL_SHIFT |
521 src_clk_div << SPI0_DIV_SHIFT);
522 break;
Simon Glass8d32f4b2016-01-21 19:43:38 -0700523 case SCLK_SPI1:
Simon Glass421358c2015-08-30 16:55:31 -0600524 rk_clrsetreg(&cru->cru_clksel_con[25],
525 SPI1_PLL_MASK << SPI1_PLL_SHIFT |
526 SPI1_DIV_MASK << SPI1_DIV_SHIFT,
527 SPI1_PLL_SELECT_GENERAL << SPI1_PLL_SHIFT |
528 src_clk_div << SPI1_DIV_SHIFT);
529 break;
Simon Glass8d32f4b2016-01-21 19:43:38 -0700530 case SCLK_SPI2:
Simon Glass421358c2015-08-30 16:55:31 -0600531 rk_clrsetreg(&cru->cru_clksel_con[39],
532 SPI2_PLL_MASK << SPI2_PLL_SHIFT |
533 SPI2_DIV_MASK << SPI2_DIV_SHIFT,
534 SPI2_PLL_SELECT_GENERAL << SPI2_PLL_SHIFT |
535 src_clk_div << SPI2_DIV_SHIFT);
536 break;
537 default:
538 return -EINVAL;
539 }
540
Simon Glassafe0cb02016-01-21 19:43:39 -0700541 return rockchip_spi_get_clk(cru, gclk_rate, periph);
Simon Glass421358c2015-08-30 16:55:31 -0600542}
543
Simon Glass398ced12016-01-21 19:43:40 -0700544static ulong rk3288_get_periph_rate(struct udevice *dev, int periph)
545{
546 struct rk3288_clk_priv *priv = dev_get_priv(dev);
547 struct udevice *gclk;
548 ulong new_rate, gclk_rate;
549 int ret;
550
Simon Glass344f3662016-01-21 19:43:41 -0700551 ret = rkclk_get_clk(CLK_GENERAL, &gclk);
Simon Glass398ced12016-01-21 19:43:40 -0700552 if (ret)
553 return ret;
554 gclk_rate = clk_get_rate(gclk);
555 switch (periph) {
556 case HCLK_EMMC:
Simon Glassd4a8a682016-01-21 19:43:45 -0700557 case HCLK_SDMMC:
Simon Glass398ced12016-01-21 19:43:40 -0700558 case HCLK_SDIO0:
Simon Glass398ced12016-01-21 19:43:40 -0700559 new_rate = rockchip_mmc_get_clk(priv->cru, gclk_rate, periph);
560 break;
561 case SCLK_SPI0:
562 case SCLK_SPI1:
563 case SCLK_SPI2:
564 new_rate = rockchip_spi_get_clk(priv->cru, gclk_rate, periph);
565 break;
566 case PCLK_I2C0:
567 case PCLK_I2C1:
568 case PCLK_I2C2:
569 case PCLK_I2C3:
570 case PCLK_I2C4:
571 case PCLK_I2C5:
572 return gclk_rate;
573 default:
574 return -ENOENT;
575 }
576
577 return new_rate;
578}
579
Masahiro Yamadaecf20f62016-01-13 13:16:10 +0900580static ulong rk3288_set_periph_rate(struct udevice *dev, int periph, ulong rate)
Simon Glass421358c2015-08-30 16:55:31 -0600581{
582 struct rk3288_clk_priv *priv = dev_get_priv(dev);
Simon Glass8d32f4b2016-01-21 19:43:38 -0700583 struct udevice *gclk;
584 ulong new_rate, gclk_rate;
585 int ret;
Simon Glass421358c2015-08-30 16:55:31 -0600586
Simon Glass344f3662016-01-21 19:43:41 -0700587 ret = rkclk_get_clk(CLK_GENERAL, &gclk);
Simon Glass8d32f4b2016-01-21 19:43:38 -0700588 if (ret)
589 return ret;
590 gclk_rate = clk_get_rate(gclk);
Simon Glass421358c2015-08-30 16:55:31 -0600591 switch (periph) {
Simon Glass8d32f4b2016-01-21 19:43:38 -0700592 case HCLK_EMMC:
593 case HCLK_SDMMC:
594 case HCLK_SDIO0:
595 new_rate = rockchip_mmc_set_clk(priv->cru, gclk_rate, periph,
596 rate);
Simon Glass421358c2015-08-30 16:55:31 -0600597 break;
Simon Glass8d32f4b2016-01-21 19:43:38 -0700598 case SCLK_SPI0:
599 case SCLK_SPI1:
600 case SCLK_SPI2:
601 new_rate = rockchip_spi_set_clk(priv->cru, gclk_rate, periph,
602 rate);
Simon Glass421358c2015-08-30 16:55:31 -0600603 break;
604 default:
605 return -ENOENT;
606 }
607
608 return new_rate;
609}
610
611static struct clk_ops rk3288_clk_ops = {
612 .get_rate = rk3288_clk_get_rate,
613 .set_rate = rk3288_clk_set_rate,
614 .set_periph_rate = rk3288_set_periph_rate,
Simon Glass398ced12016-01-21 19:43:40 -0700615 .get_periph_rate = rk3288_get_periph_rate,
Simon Glass421358c2015-08-30 16:55:31 -0600616};
617
618static int rk3288_clk_probe(struct udevice *dev)
619{
620 struct rk3288_clk_plat *plat = dev_get_platdata(dev);
621 struct rk3288_clk_priv *priv = dev_get_priv(dev);
622
623 if (plat->clk_id != CLK_OSC) {
624 struct rk3288_clk_priv *parent_priv = dev_get_priv(dev->parent);
625
626 priv->cru = parent_priv->cru;
627 priv->grf = parent_priv->grf;
628 return 0;
629 }
630 priv->cru = (struct rk3288_cru *)dev_get_addr(dev);
631 priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
632#ifdef CONFIG_SPL_BUILD
633 rkclk_init(priv->cru, priv->grf);
634#endif
635
636 return 0;
637}
638
639static const char *const clk_name[CLK_COUNT] = {
640 "osc",
641 "apll",
642 "dpll",
643 "cpll",
644 "gpll",
645 "mpll",
646};
647
648static int rk3288_clk_bind(struct udevice *dev)
649{
650 struct rk3288_clk_plat *plat = dev_get_platdata(dev);
651 int pll, ret;
652
653 /* We only need to set up the root clock */
654 if (dev->of_offset == -1) {
655 plat->clk_id = CLK_OSC;
656 return 0;
657 }
658
659 /* Create devices for P main clocks */
660 for (pll = 1; pll < CLK_COUNT; pll++) {
661 struct udevice *child;
662 struct rk3288_clk_plat *cplat;
663
664 debug("%s %s\n", __func__, clk_name[pll]);
665 ret = device_bind_driver(dev, "clk_rk3288", clk_name[pll],
666 &child);
667 if (ret)
668 return ret;
669 cplat = dev_get_platdata(child);
670 cplat->clk_id = pll;
671 }
672
673 /* The reset driver does not have a device node, so bind it here */
674 ret = device_bind_driver(gd->dm_root, "rk3288_reset", "reset", &dev);
675 if (ret)
676 debug("Warning: No RK3288 reset driver: ret=%d\n", ret);
677
678 return 0;
679}
680
681static const struct udevice_id rk3288_clk_ids[] = {
682 { .compatible = "rockchip,rk3288-cru" },
683 { }
684};
685
686U_BOOT_DRIVER(clk_rk3288) = {
687 .name = "clk_rk3288",
688 .id = UCLASS_CLK,
689 .of_match = rk3288_clk_ids,
690 .priv_auto_alloc_size = sizeof(struct rk3288_clk_priv),
691 .platdata_auto_alloc_size = sizeof(struct rk3288_clk_plat),
692 .ops = &rk3288_clk_ops,
693 .bind = rk3288_clk_bind,
694 .probe = rk3288_clk_probe,
695};