1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2018 Emmanuel Vadot <[email protected]>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * $FreeBSD$
28 */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/bus.h>
36
37 #include <dev/extres/clk/clk.h>
38
39 #include <arm64/rockchip/clk/rk_clk_pll.h>
40
41 #include "clkdev_if.h"
42
43 struct rk_clk_pll_sc {
44 uint32_t base_offset;
45
46 uint32_t gate_offset;
47 uint32_t gate_shift;
48
49 uint32_t mode_reg;
50 uint32_t mode_shift;
51
52 uint32_t flags;
53
54 struct rk_clk_pll_rate *rates;
55 struct rk_clk_pll_rate *frac_rates;
56 };
57
58 #define WRITE4(_clk, off, val) \
59 CLKDEV_WRITE_4(clknode_get_device(_clk), off, val)
60 #define READ4(_clk, off, val) \
61 CLKDEV_READ_4(clknode_get_device(_clk), off, val)
62 #define DEVICE_LOCK(_clk) \
63 CLKDEV_DEVICE_LOCK(clknode_get_device(_clk))
64 #define DEVICE_UNLOCK(_clk) \
65 CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk))
66
67 #define RK_CLK_PLL_MASK_SHIFT 16
68
69 #if 0
70 #define dprintf(format, arg...) \
71 printf("%s:(%s)" format, __func__, clknode_get_name(clk), arg)
72 #else
73 #define dprintf(format, arg...)
74 #endif
75
76 static int
rk_clk_pll_set_gate(struct clknode * clk,bool enable)77 rk_clk_pll_set_gate(struct clknode *clk, bool enable)
78 {
79 struct rk_clk_pll_sc *sc;
80 uint32_t val = 0;
81
82 sc = clknode_get_softc(clk);
83
84 if ((sc->flags & RK_CLK_PLL_HAVE_GATE) == 0)
85 return (0);
86
87 dprintf("%sabling gate\n", enable ? "En" : "Dis");
88 if (!enable)
89 val |= 1 << sc->gate_shift;
90 dprintf("sc->gate_shift: %x\n", sc->gate_shift);
91 val |= (1 << sc->gate_shift) << RK_CLK_PLL_MASK_SHIFT;
92 dprintf("Write: gate_offset=%x, val=%x\n", sc->gate_offset, val);
93 DEVICE_LOCK(clk);
94 WRITE4(clk, sc->gate_offset, val);
95 DEVICE_UNLOCK(clk);
96
97 return (0);
98 }
99
100 /* CON0 */
101 #define RK3066_CLK_PLL_REFDIV_SHIFT 8
102 #define RK3066_CLK_PLL_REFDIV_MASK 0x3F00
103 #define RK3066_CLK_PLL_POSTDIV_SHIFT 0
104 #define RK3066_CLK_PLL_POSTDIV_MASK 0x000F
105 /* CON1 */
106 #define RK3066_CLK_PLL_LOCK_MASK (1U << 31)
107 #define RK3066_CLK_PLL_FBDIV_SHIFT 0
108 #define RK3066_CLK_PLL_FBDIV_MASK 0x0FFF
109 /* CON2 */
110
111 /* CON3 */
112 #define RK3066_CLK_PLL_RESET (1 << 5)
113 #define RK3066_CLK_PLL_TEST (1 << 4)
114 #define RK3066_CLK_PLL_ENSAT (1 << 3)
115 #define RK3066_CLK_PLL_FASTEN (1 << 2)
116 #define RK3066_CLK_PLL_POWER_DOWN (1 << 1)
117 #define RK3066_CLK_PLL_BYPASS (1 << 0)
118
119 #define RK3066_CLK_PLL_MODE_SLOW 0
120 #define RK3066_CLK_PLL_MODE_NORMAL 1
121 #define RK3066_CLK_PLL_MODE_DEEP_SLOW 2
122 #define RK3066_CLK_PLL_MODE_MASK 0x3
123
124 static int
rk3066_clk_pll_init(struct clknode * clk,device_t dev)125 rk3066_clk_pll_init(struct clknode *clk, device_t dev)
126 {
127 struct rk_clk_pll_sc *sc;
128 uint32_t reg;
129
130 sc = clknode_get_softc(clk);
131
132 DEVICE_LOCK(clk);
133 READ4(clk, sc->mode_reg, ®);
134 DEVICE_UNLOCK(clk);
135
136 reg = (reg >> sc->mode_shift) & RK3066_CLK_PLL_MODE_MASK;
137 clknode_init_parent_idx(clk, reg);
138
139 return (0);
140 }
141
142 static int
rk3066_clk_pll_set_mux(struct clknode * clk,int idx)143 rk3066_clk_pll_set_mux(struct clknode *clk, int idx)
144 {
145 uint32_t reg;
146 struct rk_clk_pll_sc *sc;
147
148 sc = clknode_get_softc(clk);
149
150 reg = (idx & RK3066_CLK_PLL_MODE_MASK) << sc->mode_shift;
151 reg |= (RK3066_CLK_PLL_MODE_MASK << sc->mode_shift) <<
152 RK_CLK_PLL_MASK_SHIFT;
153
154 DEVICE_LOCK(clk);
155 WRITE4(clk, sc->mode_reg, reg);
156 DEVICE_UNLOCK(clk);
157 return(0);
158 }
159
160 static int
rk3066_clk_pll_recalc(struct clknode * clk,uint64_t * freq)161 rk3066_clk_pll_recalc(struct clknode *clk, uint64_t *freq)
162 {
163 struct rk_clk_pll_sc *sc;
164 uint64_t rate;
165 uint32_t refdiv, fbdiv, postdiv;
166 uint32_t raw0, raw1, raw2, reg;
167
168 sc = clknode_get_softc(clk);
169
170 DEVICE_LOCK(clk);
171
172 READ4(clk, sc->base_offset, &raw0);
173 READ4(clk, sc->base_offset + 4, &raw1);
174 READ4(clk, sc->base_offset + 8, &raw2);
175 READ4(clk, sc->mode_reg, ®);
176
177 DEVICE_UNLOCK(clk);
178
179 reg = (reg >> sc->mode_shift) & RK3066_CLK_PLL_MODE_MASK;
180
181 if (reg != RK3066_CLK_PLL_MODE_NORMAL)
182 return (0);
183
184 if (!(raw1 & RK3066_CLK_PLL_LOCK_MASK)) {
185 *freq = 0;
186 return (0);
187 }
188
189 /* TODO MUX */
190 refdiv = (raw0 & RK3066_CLK_PLL_REFDIV_MASK) >>
191 RK3066_CLK_PLL_REFDIV_SHIFT;
192 refdiv += 1;
193 postdiv = (raw0 & RK3066_CLK_PLL_POSTDIV_MASK) >>
194 RK3066_CLK_PLL_POSTDIV_SHIFT;
195 postdiv += 1;
196 fbdiv = (raw1 & RK3066_CLK_PLL_FBDIV_MASK) >>
197 RK3066_CLK_PLL_FBDIV_SHIFT;
198 fbdiv += 1;
199
200 rate = *freq * fbdiv;
201 rate /= refdiv;
202 *freq = rate / postdiv;
203
204 return (0);
205 }
206
207 static int
rk3066_clk_pll_set_freq(struct clknode * clk,uint64_t fparent,uint64_t * fout,int flags,int * stop)208 rk3066_clk_pll_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout,
209 int flags, int *stop)
210 {
211 struct rk_clk_pll_rate *rates;
212 struct rk_clk_pll_sc *sc;
213 uint32_t reg;
214 int rv, timeout;
215
216 sc = clknode_get_softc(clk);
217
218 if (sc->rates == NULL)
219 return (EINVAL);
220
221 for (rates = sc->rates; rates->freq; rates++) {
222 if (rates->freq == *fout)
223 break;
224 }
225 if (rates->freq == 0) {
226 *stop = 1;
227 return (EINVAL);
228 }
229
230 DEVICE_LOCK(clk);
231
232 /* Setting to slow mode during frequency change */
233 reg = (RK3066_CLK_PLL_MODE_MASK << sc->mode_shift) <<
234 RK_CLK_PLL_MASK_SHIFT;
235 dprintf("Set PLL_MODEREG to %x\n", reg);
236 WRITE4(clk, sc->mode_reg, reg);
237
238 /* Reset PLL */
239 WRITE4(clk, sc->base_offset + 12, RK3066_CLK_PLL_RESET |
240 RK3066_CLK_PLL_RESET << RK_CLK_PLL_MASK_SHIFT);
241
242 /* Setting postdiv and refdiv */
243 reg = 0;
244 reg |= RK3066_CLK_PLL_POSTDIV_MASK << 16;
245 reg |= (rates->postdiv1 - 1) << RK3066_CLK_PLL_POSTDIV_SHIFT;
246
247 reg |= RK3066_CLK_PLL_REFDIV_MASK << 16;
248 reg |= (rates->refdiv - 1)<< RK3066_CLK_PLL_REFDIV_SHIFT;
249
250 dprintf("Set PLL_CON0 to %x\n", reg);
251 WRITE4(clk, sc->base_offset, reg);
252
253
254 /* Setting fbdiv (no write mask)*/
255 READ4(clk, sc->base_offset + 4, ®);
256 reg &= ~RK3066_CLK_PLL_FBDIV_MASK;
257 reg |= RK3066_CLK_PLL_FBDIV_MASK << 16;
258 reg = (rates->fbdiv - 1) << RK3066_CLK_PLL_FBDIV_SHIFT;
259
260 dprintf("Set PLL_CON1 to %x\n", reg);
261 WRITE4(clk, sc->base_offset + 0x4, reg);
262
263 /* PLL loop bandwidth adjust */
264 reg = rates->bwadj - 1;
265 dprintf("Set PLL_CON2 to %x (%x)\n", reg, rates->bwadj);
266 WRITE4(clk, sc->base_offset + 0x8, reg);
267
268 /* Clear reset */
269 WRITE4(clk, sc->base_offset + 12,
270 RK3066_CLK_PLL_RESET << RK_CLK_PLL_MASK_SHIFT);
271 DELAY(100000);
272
273 /* Reading lock */
274 for (timeout = 1000; timeout >= 0; timeout--) {
275 READ4(clk, sc->base_offset + 0x4, ®);
276 if ((reg & RK3066_CLK_PLL_LOCK_MASK) != 0)
277 break;
278 DELAY(1);
279 }
280
281 rv = 0;
282 if (timeout < 0) {
283 device_printf(clknode_get_device(clk),
284 "%s - Timedout while waiting for lock.\n",
285 clknode_get_name(clk));
286 dprintf("PLL_CON1: %x\n", reg);
287 rv = ETIMEDOUT;
288 }
289
290 /* Set back to normal mode */
291 reg = (RK3066_CLK_PLL_MODE_NORMAL << sc->mode_shift);
292 reg |= (RK3066_CLK_PLL_MODE_MASK << sc->mode_shift) <<
293 RK_CLK_PLL_MASK_SHIFT;
294 dprintf("Set PLL_MODEREG to %x\n", reg);
295 WRITE4(clk, sc->mode_reg, reg);
296
297 DEVICE_UNLOCK(clk);
298 *stop = 1;
299 rv = clknode_set_parent_by_idx(clk, 1);
300 return (rv);
301 }
302
303 static clknode_method_t rk3066_clk_pll_clknode_methods[] = {
304 /* Device interface */
305 CLKNODEMETHOD(clknode_init, rk3066_clk_pll_init),
306 CLKNODEMETHOD(clknode_set_gate, rk_clk_pll_set_gate),
307 CLKNODEMETHOD(clknode_recalc_freq, rk3066_clk_pll_recalc),
308 CLKNODEMETHOD(clknode_set_freq, rk3066_clk_pll_set_freq),
309 CLKNODEMETHOD(clknode_set_mux, rk3066_clk_pll_set_mux),
310 CLKNODEMETHOD_END
311 };
312
313 DEFINE_CLASS_1(rk3066_clk_pll_clknode, rk3066_clk_pll_clknode_class,
314 rk3066_clk_pll_clknode_methods, sizeof(struct rk_clk_pll_sc), clknode_class);
315
316 int
rk3066_clk_pll_register(struct clkdom * clkdom,struct rk_clk_pll_def * clkdef)317 rk3066_clk_pll_register(struct clkdom *clkdom, struct rk_clk_pll_def *clkdef)
318 {
319 struct clknode *clk;
320 struct rk_clk_pll_sc *sc;
321
322 clk = clknode_create(clkdom, &rk3066_clk_pll_clknode_class,
323 &clkdef->clkdef);
324 if (clk == NULL)
325 return (1);
326
327 sc = clknode_get_softc(clk);
328
329 sc->base_offset = clkdef->base_offset;
330 sc->gate_offset = clkdef->gate_offset;
331 sc->gate_shift = clkdef->gate_shift;
332 sc->mode_reg = clkdef->mode_reg;
333 sc->mode_shift = clkdef->mode_shift;
334 sc->flags = clkdef->flags;
335 sc->rates = clkdef->rates;
336 sc->frac_rates = clkdef->frac_rates;
337
338 clknode_register(clkdom, clk);
339
340 return (0);
341 }
342
343 #define RK3328_CLK_PLL_FBDIV_OFFSET 0
344 #define RK3328_CLK_PLL_FBDIV_SHIFT 0
345 #define RK3328_CLK_PLL_FBDIV_MASK 0xFFF
346
347 #define RK3328_CLK_PLL_POSTDIV1_OFFSET 0
348 #define RK3328_CLK_PLL_POSTDIV1_SHIFT 12
349 #define RK3328_CLK_PLL_POSTDIV1_MASK 0x7000
350
351 #define RK3328_CLK_PLL_DSMPD_OFFSET 4
352 #define RK3328_CLK_PLL_DSMPD_SHIFT 12
353 #define RK3328_CLK_PLL_DSMPD_MASK 0x1000
354
355 #define RK3328_CLK_PLL_REFDIV_OFFSET 4
356 #define RK3328_CLK_PLL_REFDIV_SHIFT 0
357 #define RK3328_CLK_PLL_REFDIV_MASK 0x3F
358
359 #define RK3328_CLK_PLL_POSTDIV2_OFFSET 4
360 #define RK3328_CLK_PLL_POSTDIV2_SHIFT 6
361 #define RK3328_CLK_PLL_POSTDIV2_MASK 0x1C0
362
363 #define RK3328_CLK_PLL_FRAC_OFFSET 8
364 #define RK3328_CLK_PLL_FRAC_SHIFT 0
365 #define RK3328_CLK_PLL_FRAC_MASK 0xFFFFFF
366
367 #define RK3328_CLK_PLL_LOCK_MASK 0x400
368
369 #define RK3328_CLK_PLL_MODE_SLOW 0
370 #define RK3328_CLK_PLL_MODE_NORMAL 1
371 #define RK3328_CLK_PLL_MODE_MASK 0x1
372
373 static int
rk3328_clk_pll_init(struct clknode * clk,device_t dev)374 rk3328_clk_pll_init(struct clknode *clk, device_t dev)
375 {
376 struct rk_clk_pll_sc *sc;
377
378 sc = clknode_get_softc(clk);
379
380 clknode_init_parent_idx(clk, 0);
381
382 return (0);
383 }
384
385 static int
rk3328_clk_pll_recalc(struct clknode * clk,uint64_t * freq)386 rk3328_clk_pll_recalc(struct clknode *clk, uint64_t *freq)
387 {
388 struct rk_clk_pll_sc *sc;
389 uint64_t rate;
390 uint32_t dsmpd, refdiv, fbdiv;
391 uint32_t postdiv1, postdiv2, frac;
392 uint32_t raw1, raw2, raw3;
393
394 sc = clknode_get_softc(clk);
395
396 DEVICE_LOCK(clk);
397
398 READ4(clk, sc->base_offset, &raw1);
399 READ4(clk, sc->base_offset + 4, &raw2);
400 READ4(clk, sc->base_offset + 8, &raw3);
401
402 fbdiv = (raw1 & RK3328_CLK_PLL_FBDIV_MASK) >> RK3328_CLK_PLL_FBDIV_SHIFT;
403 postdiv1 = (raw1 & RK3328_CLK_PLL_POSTDIV1_MASK) >> RK3328_CLK_PLL_POSTDIV1_SHIFT;
404
405 dsmpd = (raw2 & RK3328_CLK_PLL_DSMPD_MASK) >> RK3328_CLK_PLL_DSMPD_SHIFT;
406 refdiv = (raw2 & RK3328_CLK_PLL_REFDIV_MASK) >> RK3328_CLK_PLL_REFDIV_SHIFT;
407 postdiv2 = (raw2 & RK3328_CLK_PLL_POSTDIV2_MASK) >> RK3328_CLK_PLL_POSTDIV2_SHIFT;
408
409 frac = (raw3 & RK3328_CLK_PLL_FRAC_MASK) >> RK3328_CLK_PLL_FRAC_SHIFT;
410
411 DEVICE_UNLOCK(clk);
412
413 rate = *freq * fbdiv / refdiv;
414 if (dsmpd == 0) {
415 /* Fractional mode */
416 uint64_t frac_rate;
417
418 frac_rate = *freq * frac / refdiv;
419 rate += frac_rate >> 24;
420 }
421
422 *freq = rate / postdiv1 / postdiv2;
423
424 if (*freq % 2)
425 *freq = *freq + 1;
426
427 return (0);
428 }
429
430 static int
rk3328_clk_pll_set_freq(struct clknode * clk,uint64_t fparent,uint64_t * fout,int flags,int * stop)431 rk3328_clk_pll_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout,
432 int flags, int *stop)
433 {
434 struct rk_clk_pll_rate *rates;
435 struct rk_clk_pll_sc *sc;
436 uint32_t reg;
437 int timeout;
438
439 sc = clknode_get_softc(clk);
440
441 if (sc->rates)
442 rates = sc->rates;
443 else if (sc->frac_rates)
444 rates = sc->frac_rates;
445 else
446 return (EINVAL);
447
448 for (; rates->freq; rates++) {
449 if (rates->freq == *fout)
450 break;
451 }
452 if (rates->freq == 0) {
453 *stop = 1;
454 return (EINVAL);
455 }
456
457 DEVICE_LOCK(clk);
458
459 /* Setting to slow mode during frequency change */
460 reg = (RK3328_CLK_PLL_MODE_MASK << sc->mode_shift) <<
461 RK_CLK_PLL_MASK_SHIFT;
462 dprintf("Set PLL_MODEREG to %x\n", reg);
463 WRITE4(clk, sc->mode_reg, reg);
464
465 /* Setting postdiv1 and fbdiv */
466 reg = (rates->postdiv1 << RK3328_CLK_PLL_POSTDIV1_SHIFT) |
467 (rates->fbdiv << RK3328_CLK_PLL_FBDIV_SHIFT);
468 reg |= (RK3328_CLK_PLL_POSTDIV1_MASK | RK3328_CLK_PLL_FBDIV_MASK) << 16;
469 dprintf("Set PLL_CON0 to %x\n", reg);
470 WRITE4(clk, sc->base_offset, reg);
471
472 /* Setting dsmpd, postdiv2 and refdiv */
473 reg = (rates->dsmpd << RK3328_CLK_PLL_DSMPD_SHIFT) |
474 (rates->postdiv2 << RK3328_CLK_PLL_POSTDIV2_SHIFT) |
475 (rates->refdiv << RK3328_CLK_PLL_REFDIV_SHIFT);
476 reg |= (RK3328_CLK_PLL_DSMPD_MASK |
477 RK3328_CLK_PLL_POSTDIV2_MASK |
478 RK3328_CLK_PLL_REFDIV_MASK) << RK_CLK_PLL_MASK_SHIFT;
479 dprintf("Set PLL_CON1 to %x\n", reg);
480 WRITE4(clk, sc->base_offset + 0x4, reg);
481
482 /* Setting frac */
483 READ4(clk, sc->base_offset + 0x8, ®);
484 reg &= ~RK3328_CLK_PLL_FRAC_MASK;
485 reg |= rates->frac << RK3328_CLK_PLL_FRAC_SHIFT;
486 dprintf("Set PLL_CON2 to %x\n", reg);
487 WRITE4(clk, sc->base_offset + 0x8, reg);
488
489 /* Reading lock */
490 for (timeout = 1000; timeout; timeout--) {
491 READ4(clk, sc->base_offset + 0x4, ®);
492 if ((reg & RK3328_CLK_PLL_LOCK_MASK) == 0)
493 break;
494 DELAY(1);
495 }
496
497 /* Set back to normal mode */
498 reg = (RK3328_CLK_PLL_MODE_NORMAL << sc->mode_shift);
499 reg |= (RK3328_CLK_PLL_MODE_MASK << sc->mode_shift) <<
500 RK_CLK_PLL_MASK_SHIFT;
501 dprintf("Set PLL_MODEREG to %x\n", reg);
502 WRITE4(clk, sc->mode_reg, reg);
503
504 DEVICE_UNLOCK(clk);
505
506 *stop = 1;
507 return (0);
508 }
509
510 static clknode_method_t rk3328_clk_pll_clknode_methods[] = {
511 /* Device interface */
512 CLKNODEMETHOD(clknode_init, rk3328_clk_pll_init),
513 CLKNODEMETHOD(clknode_set_gate, rk_clk_pll_set_gate),
514 CLKNODEMETHOD(clknode_recalc_freq, rk3328_clk_pll_recalc),
515 CLKNODEMETHOD(clknode_set_freq, rk3328_clk_pll_set_freq),
516 CLKNODEMETHOD_END
517 };
518
519 DEFINE_CLASS_1(rk3328_clk_pll_clknode, rk3328_clk_pll_clknode_class,
520 rk3328_clk_pll_clknode_methods, sizeof(struct rk_clk_pll_sc), clknode_class);
521
522 int
rk3328_clk_pll_register(struct clkdom * clkdom,struct rk_clk_pll_def * clkdef)523 rk3328_clk_pll_register(struct clkdom *clkdom, struct rk_clk_pll_def *clkdef)
524 {
525 struct clknode *clk;
526 struct rk_clk_pll_sc *sc;
527
528 clk = clknode_create(clkdom, &rk3328_clk_pll_clknode_class,
529 &clkdef->clkdef);
530 if (clk == NULL)
531 return (1);
532
533 sc = clknode_get_softc(clk);
534
535 sc->base_offset = clkdef->base_offset;
536 sc->gate_offset = clkdef->gate_offset;
537 sc->gate_shift = clkdef->gate_shift;
538 sc->mode_reg = clkdef->mode_reg;
539 sc->mode_shift = clkdef->mode_shift;
540 sc->flags = clkdef->flags;
541 sc->rates = clkdef->rates;
542 sc->frac_rates = clkdef->frac_rates;
543
544 clknode_register(clkdom, clk);
545
546 return (0);
547 }
548
549 #define RK3399_CLK_PLL_FBDIV_OFFSET 0
550 #define RK3399_CLK_PLL_FBDIV_SHIFT 0
551 #define RK3399_CLK_PLL_FBDIV_MASK 0xFFF
552
553 #define RK3399_CLK_PLL_POSTDIV2_OFFSET 4
554 #define RK3399_CLK_PLL_POSTDIV2_SHIFT 12
555 #define RK3399_CLK_PLL_POSTDIV2_MASK 0x7000
556
557 #define RK3399_CLK_PLL_POSTDIV1_OFFSET 4
558 #define RK3399_CLK_PLL_POSTDIV1_SHIFT 8
559 #define RK3399_CLK_PLL_POSTDIV1_MASK 0x700
560
561 #define RK3399_CLK_PLL_REFDIV_OFFSET 4
562 #define RK3399_CLK_PLL_REFDIV_SHIFT 0
563 #define RK3399_CLK_PLL_REFDIV_MASK 0x3F
564
565 #define RK3399_CLK_PLL_FRAC_OFFSET 8
566 #define RK3399_CLK_PLL_FRAC_SHIFT 0
567 #define RK3399_CLK_PLL_FRAC_MASK 0xFFFFFF
568
569 #define RK3399_CLK_PLL_DSMPD_OFFSET 0xC
570 #define RK3399_CLK_PLL_DSMPD_SHIFT 3
571 #define RK3399_CLK_PLL_DSMPD_MASK 0x8
572
573 #define RK3399_CLK_PLL_LOCK_OFFSET 8
574 #define RK3399_CLK_PLL_LOCK_MASK 0x400
575
576 #define RK3399_CLK_PLL_MODE_OFFSET 0xC
577 #define RK3399_CLK_PLL_MODE_MASK 0x300
578 #define RK3399_CLK_PLL_MODE_SLOW 0
579 #define RK3399_CLK_PLL_MODE_NORMAL 1
580 #define RK3399_CLK_PLL_MODE_DEEPSLOW 2
581 #define RK3399_CLK_PLL_MODE_SHIFT 8
582
583 #define RK3399_CLK_PLL_WRITE_MASK 0xFFFF0000
584
585 static int
rk3399_clk_pll_init(struct clknode * clk,device_t dev)586 rk3399_clk_pll_init(struct clknode *clk, device_t dev)
587 {
588 struct rk_clk_pll_sc *sc;
589
590 sc = clknode_get_softc(clk);
591 clknode_init_parent_idx(clk, 0);
592
593 return (0);
594 }
595
596 static int
rk3399_clk_pll_recalc(struct clknode * clk,uint64_t * freq)597 rk3399_clk_pll_recalc(struct clknode *clk, uint64_t *freq)
598 {
599 struct rk_clk_pll_sc *sc;
600 uint32_t dsmpd, refdiv, fbdiv;
601 uint32_t postdiv1, postdiv2, fracdiv;
602 uint32_t con1, con2, con3, con4;
603 uint64_t foutvco;
604 uint32_t mode;
605 sc = clknode_get_softc(clk);
606
607 DEVICE_LOCK(clk);
608 READ4(clk, sc->base_offset, &con1);
609 READ4(clk, sc->base_offset + 4, &con2);
610 READ4(clk, sc->base_offset + 8, &con3);
611 READ4(clk, sc->base_offset + 0xC, &con4);
612 DEVICE_UNLOCK(clk);
613
614 /*
615 * if we are in slow mode the output freq
616 * is the parent one, the 24Mhz external oscillator
617 * if we are in deep mode the output freq is 32.768khz
618 */
619 mode = (con4 & RK3399_CLK_PLL_MODE_MASK) >> RK3399_CLK_PLL_MODE_SHIFT;
620 if (mode == RK3399_CLK_PLL_MODE_SLOW) {
621 dprintf("pll in slow mode, con4=%x\n", con4);
622 return (0);
623 } else if (mode == RK3399_CLK_PLL_MODE_DEEPSLOW) {
624 dprintf("pll in deep slow, con4=%x\n", con4);
625 *freq = 32768;
626 return (0);
627 }
628
629 dprintf("con0: %x\n", con1);
630 dprintf("con1: %x\n", con2);
631 dprintf("con2: %x\n", con3);
632 dprintf("con3: %x\n", con4);
633
634 fbdiv = (con1 & RK3399_CLK_PLL_FBDIV_MASK)
635 >> RK3399_CLK_PLL_FBDIV_SHIFT;
636
637 postdiv1 = (con2 & RK3399_CLK_PLL_POSTDIV1_MASK)
638 >> RK3399_CLK_PLL_POSTDIV1_SHIFT;
639 postdiv2 = (con2 & RK3399_CLK_PLL_POSTDIV2_MASK)
640 >> RK3399_CLK_PLL_POSTDIV2_SHIFT;
641 refdiv = (con2 & RK3399_CLK_PLL_REFDIV_MASK)
642 >> RK3399_CLK_PLL_REFDIV_SHIFT;
643
644 fracdiv = (con3 & RK3399_CLK_PLL_FRAC_MASK)
645 >> RK3399_CLK_PLL_FRAC_SHIFT;
646 fracdiv >>= 24;
647
648 dsmpd = (con4 & RK3399_CLK_PLL_DSMPD_MASK) >> RK3399_CLK_PLL_DSMPD_SHIFT;
649
650 dprintf("fbdiv: %d\n", fbdiv);
651 dprintf("postdiv1: %d\n", postdiv1);
652 dprintf("postdiv2: %d\n", postdiv2);
653 dprintf("refdiv: %d\n", refdiv);
654 dprintf("fracdiv: %d\n", fracdiv);
655 dprintf("dsmpd: %d\n", dsmpd);
656
657 dprintf("parent freq=%ju\n", *freq);
658
659 if (dsmpd == 0) {
660 /* Fractional mode */
661 foutvco = *freq / refdiv * (fbdiv + fracdiv);
662 } else {
663 /* Integer mode */
664 foutvco = *freq / refdiv * fbdiv;
665 }
666 dprintf("foutvco: %ju\n", foutvco);
667
668 *freq = foutvco / postdiv1 / postdiv2;
669 dprintf("freq: %ju\n", *freq);
670
671 return (0);
672 }
673
674 static int
rk3399_clk_pll_set_freq(struct clknode * clk,uint64_t fparent,uint64_t * fout,int flags,int * stop)675 rk3399_clk_pll_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout,
676 int flags, int *stop)
677 {
678 struct rk_clk_pll_rate *rates;
679 struct rk_clk_pll_sc *sc;
680 uint32_t reg;
681 int timeout;
682
683 sc = clknode_get_softc(clk);
684
685 if (sc->rates)
686 rates = sc->rates;
687 else if (sc->frac_rates)
688 rates = sc->frac_rates;
689 else
690 return (EINVAL);
691
692 for (; rates->freq; rates++) {
693 if (rates->freq == *fout)
694 break;
695 }
696 if (rates->freq == 0) {
697 *stop = 1;
698 return (EINVAL);
699 }
700
701 DEVICE_LOCK(clk);
702
703 /* Set to slow mode during frequency change */
704 reg = RK3399_CLK_PLL_MODE_SLOW << RK3399_CLK_PLL_MODE_SHIFT;
705 reg |= RK3399_CLK_PLL_MODE_MASK << RK_CLK_PLL_MASK_SHIFT;
706 WRITE4(clk, sc->base_offset + 0xC, reg);
707
708 /* Setting fbdiv */
709 reg = rates->fbdiv << RK3399_CLK_PLL_FBDIV_SHIFT;
710 reg |= RK3399_CLK_PLL_FBDIV_MASK << RK_CLK_PLL_MASK_SHIFT;
711 WRITE4(clk, sc->base_offset, reg);
712
713 /* Setting postdiv1, postdiv2 and refdiv */
714 reg = rates->postdiv1 << RK3399_CLK_PLL_POSTDIV1_SHIFT;
715 reg |= rates->postdiv2 << RK3399_CLK_PLL_POSTDIV2_SHIFT;
716 reg |= rates->refdiv << RK3399_CLK_PLL_REFDIV_SHIFT;
717 reg |= (RK3399_CLK_PLL_POSTDIV1_MASK | RK3399_CLK_PLL_POSTDIV2_MASK |
718 RK3399_CLK_PLL_REFDIV_MASK) << RK_CLK_PLL_MASK_SHIFT;
719 WRITE4(clk, sc->base_offset + 0x4, reg);
720
721 /* Setting frac */
722 READ4(clk, sc->base_offset + 0x8, ®);
723 reg &= ~RK3399_CLK_PLL_FRAC_MASK;
724 reg |= rates->frac << RK3399_CLK_PLL_FRAC_SHIFT;
725 WRITE4(clk, sc->base_offset + 0x8, reg | RK3399_CLK_PLL_WRITE_MASK);
726
727 /* Set dsmpd */
728 reg = rates->dsmpd << RK3399_CLK_PLL_DSMPD_SHIFT;
729 reg |= RK3399_CLK_PLL_DSMPD_MASK << RK_CLK_PLL_MASK_SHIFT;
730 WRITE4(clk, sc->base_offset + 0xC, reg);
731
732 /* Reading lock */
733 for (timeout = 1000; timeout; timeout--) {
734 READ4(clk, sc->base_offset + RK3399_CLK_PLL_LOCK_OFFSET, ®);
735 if ((reg & RK3399_CLK_PLL_LOCK_MASK) == 0)
736 break;
737 DELAY(1);
738 }
739
740 /* Set back to normal mode */
741 reg = RK3399_CLK_PLL_MODE_NORMAL << RK3399_CLK_PLL_MODE_SHIFT;
742 reg |= RK3399_CLK_PLL_MODE_MASK << RK_CLK_PLL_MASK_SHIFT;
743 WRITE4(clk, sc->base_offset + 0xC, reg);
744
745 DEVICE_UNLOCK(clk);
746
747 *stop = 1;
748 return (0);
749 }
750
751 static clknode_method_t rk3399_clk_pll_clknode_methods[] = {
752 /* Device interface */
753 CLKNODEMETHOD(clknode_init, rk3399_clk_pll_init),
754 CLKNODEMETHOD(clknode_set_gate, rk_clk_pll_set_gate),
755 CLKNODEMETHOD(clknode_recalc_freq, rk3399_clk_pll_recalc),
756 CLKNODEMETHOD(clknode_set_freq, rk3399_clk_pll_set_freq),
757 CLKNODEMETHOD_END
758 };
759
760 DEFINE_CLASS_1(rk3399_clk_pll_clknode, rk3399_clk_pll_clknode_class,
761 rk3399_clk_pll_clknode_methods, sizeof(struct rk_clk_pll_sc), clknode_class);
762
763 int
rk3399_clk_pll_register(struct clkdom * clkdom,struct rk_clk_pll_def * clkdef)764 rk3399_clk_pll_register(struct clkdom *clkdom, struct rk_clk_pll_def *clkdef)
765 {
766 struct clknode *clk;
767 struct rk_clk_pll_sc *sc;
768
769 clk = clknode_create(clkdom, &rk3399_clk_pll_clknode_class,
770 &clkdef->clkdef);
771 if (clk == NULL)
772 return (1);
773
774 sc = clknode_get_softc(clk);
775
776 sc->base_offset = clkdef->base_offset;
777 sc->gate_offset = clkdef->gate_offset;
778 sc->gate_shift = clkdef->gate_shift;
779 sc->flags = clkdef->flags;
780 sc->rates = clkdef->rates;
781 sc->frac_rates = clkdef->frac_rates;
782
783 clknode_register(clkdom, clk);
784
785 return (0);
786 }
787