2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2018 Emmanuel Vadot <manu@freebsd.org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
34 #include <sys/param.h>
35 #include <sys/systm.h>
38 #include <dev/extres/clk/clk.h>
40 #include <arm64/rockchip/clk/rk_clk_pll.h>
42 #include "clkdev_if.h"
44 struct rk_clk_pll_sc {
55 struct rk_clk_pll_rate *rates;
56 struct rk_clk_pll_rate *frac_rates;
61 #define WRITE4(_clk, off, val) \
62 CLKDEV_WRITE_4(clknode_get_device(_clk), off, val)
63 #define READ4(_clk, off, val) \
64 CLKDEV_READ_4(clknode_get_device(_clk), off, val)
65 #define DEVICE_LOCK(_clk) \
66 CLKDEV_DEVICE_LOCK(clknode_get_device(_clk))
67 #define DEVICE_UNLOCK(_clk) \
68 CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk))
70 #define RK_CLK_PLL_MASK_SHIFT 16
72 /* #define dprintf(format, arg...) printf("%s:(%s)" format, __func__, clknode_get_name(clk), arg) */
73 #define dprintf(format, arg...)
76 rk_clk_pll_set_gate(struct clknode *clk, bool enable)
78 struct rk_clk_pll_sc *sc;
81 sc = clknode_get_softc(clk);
83 if ((sc->flags & RK_CLK_PLL_HAVE_GATE) == 0)
86 dprintf("%sabling gate\n", enable ? "En" : "Dis");
88 val |= 1 << sc->gate_shift;
89 dprintf("sc->gate_shift: %x\n", sc->gate_shift);
90 val |= (1 << sc->gate_shift) << RK_CLK_PLL_MASK_SHIFT;
91 dprintf("Write: gate_offset=%x, val=%x\n", sc->gate_offset, val);
93 WRITE4(clk, sc->gate_offset, val);
99 #define RK3328_CLK_PLL_FBDIV_OFFSET 0
100 #define RK3328_CLK_PLL_FBDIV_SHIFT 0
101 #define RK3328_CLK_PLL_FBDIV_MASK 0xFFF
103 #define RK3328_CLK_PLL_POSTDIV1_OFFSET 0
104 #define RK3328_CLK_PLL_POSTDIV1_SHIFT 12
105 #define RK3328_CLK_PLL_POSTDIV1_MASK 0x7000
107 #define RK3328_CLK_PLL_DSMPD_OFFSET 4
108 #define RK3328_CLK_PLL_DSMPD_SHIFT 12
109 #define RK3328_CLK_PLL_DSMPD_MASK 0x1000
111 #define RK3328_CLK_PLL_REFDIV_OFFSET 4
112 #define RK3328_CLK_PLL_REFDIV_SHIFT 0
113 #define RK3328_CLK_PLL_REFDIV_MASK 0x3F
115 #define RK3328_CLK_PLL_POSTDIV2_OFFSET 4
116 #define RK3328_CLK_PLL_POSTDIV2_SHIFT 6
117 #define RK3328_CLK_PLL_POSTDIV2_MASK 0x1C0
119 #define RK3328_CLK_PLL_FRAC_OFFSET 8
120 #define RK3328_CLK_PLL_FRAC_SHIFT 0
121 #define RK3328_CLK_PLL_FRAC_MASK 0xFFFFFF
123 #define RK3328_CLK_PLL_LOCK_MASK 0x400
125 #define RK3328_CLK_PLL_MODE_SLOW 0
126 #define RK3328_CLK_PLL_MODE_NORMAL 1
127 #define RK3328_CLK_PLL_MODE_MASK 0x1
130 rk3328_clk_pll_init(struct clknode *clk, device_t dev)
132 struct rk_clk_pll_sc *sc;
134 sc = clknode_get_softc(clk);
136 clknode_init_parent_idx(clk, 0);
142 rk3328_clk_pll_recalc(struct clknode *clk, uint64_t *freq)
144 struct rk_clk_pll_sc *sc;
146 uint32_t dsmpd, refdiv, fbdiv;
147 uint32_t postdiv1, postdiv2, frac;
148 uint32_t raw1, raw2, raw3;
150 sc = clknode_get_softc(clk);
154 READ4(clk, sc->base_offset, &raw1);
155 READ4(clk, sc->base_offset + 4, &raw2);
156 READ4(clk, sc->base_offset + 8, &raw3);
158 fbdiv = (raw1 & RK3328_CLK_PLL_FBDIV_MASK) >> RK3328_CLK_PLL_FBDIV_SHIFT;
159 postdiv1 = (raw1 & RK3328_CLK_PLL_POSTDIV1_MASK) >> RK3328_CLK_PLL_POSTDIV1_SHIFT;
161 dsmpd = (raw2 & RK3328_CLK_PLL_DSMPD_MASK) >> RK3328_CLK_PLL_DSMPD_SHIFT;
162 refdiv = (raw2 & RK3328_CLK_PLL_REFDIV_MASK) >> RK3328_CLK_PLL_REFDIV_SHIFT;
163 postdiv2 = (raw2 & RK3328_CLK_PLL_POSTDIV2_MASK) >> RK3328_CLK_PLL_POSTDIV2_SHIFT;
165 frac = (raw3 & RK3328_CLK_PLL_FRAC_MASK) >> RK3328_CLK_PLL_FRAC_SHIFT;
169 rate = *freq * fbdiv / refdiv;
171 /* Fractional mode */
174 frac_rate = *freq * frac / refdiv;
175 rate += frac_rate >> 24;
178 *freq = rate / postdiv1 / postdiv2;
187 rk3328_clk_pll_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout,
188 int flags, int *stop)
190 struct rk_clk_pll_rate *rates;
191 struct rk_clk_pll_sc *sc;
195 sc = clknode_get_softc(clk);
199 else if (sc->frac_rates)
200 rates = sc->frac_rates;
204 for (; rates->freq; rates++) {
205 if (rates->freq == *fout)
208 if (rates->freq == 0) {
215 /* Setting to slow mode during frequency change */
216 reg = (RK3328_CLK_PLL_MODE_MASK << sc->mode_shift) <<
217 RK_CLK_PLL_MASK_SHIFT;
218 dprintf("Set PLL_MODEREG to %x\n", reg);
219 WRITE4(clk, sc->mode_reg, reg);
221 /* Setting postdiv1 and fbdiv */
222 reg = (rates->postdiv1 << RK3328_CLK_PLL_POSTDIV1_SHIFT) |
223 (rates->fbdiv << RK3328_CLK_PLL_FBDIV_SHIFT);
224 reg |= (RK3328_CLK_PLL_POSTDIV1_MASK | RK3328_CLK_PLL_FBDIV_MASK) << 16;
225 dprintf("Set PLL_CON0 to %x\n", reg);
226 WRITE4(clk, sc->base_offset, reg);
228 /* Setting dsmpd, postdiv2 and refdiv */
229 reg = (rates->dsmpd << RK3328_CLK_PLL_DSMPD_SHIFT) |
230 (rates->postdiv2 << RK3328_CLK_PLL_POSTDIV2_SHIFT) |
231 (rates->refdiv << RK3328_CLK_PLL_REFDIV_SHIFT);
232 reg |= (RK3328_CLK_PLL_DSMPD_MASK |
233 RK3328_CLK_PLL_POSTDIV2_MASK |
234 RK3328_CLK_PLL_REFDIV_MASK) << RK_CLK_PLL_MASK_SHIFT;
235 dprintf("Set PLL_CON1 to %x\n", reg);
236 WRITE4(clk, sc->base_offset + 0x4, reg);
239 READ4(clk, sc->base_offset + 0x8, ®);
240 reg &= ~RK3328_CLK_PLL_FRAC_MASK;
241 reg |= rates->frac << RK3328_CLK_PLL_FRAC_SHIFT;
242 dprintf("Set PLL_CON2 to %x\n", reg);
243 WRITE4(clk, sc->base_offset + 0x8, reg);
246 for (timeout = 1000; timeout; timeout--) {
247 READ4(clk, sc->base_offset + 0x4, ®);
248 if ((reg & RK3328_CLK_PLL_LOCK_MASK) == 0)
253 /* Set back to normal mode */
254 reg = (RK3328_CLK_PLL_MODE_NORMAL << sc->mode_shift);
255 reg |= (RK3328_CLK_PLL_MODE_MASK << sc->mode_shift) <<
256 RK_CLK_PLL_MASK_SHIFT;
257 dprintf("Set PLL_MODEREG to %x\n", reg);
258 WRITE4(clk, sc->mode_reg, reg);
266 static clknode_method_t rk3328_clk_pll_clknode_methods[] = {
267 /* Device interface */
268 CLKNODEMETHOD(clknode_init, rk3328_clk_pll_init),
269 CLKNODEMETHOD(clknode_set_gate, rk_clk_pll_set_gate),
270 CLKNODEMETHOD(clknode_recalc_freq, rk3328_clk_pll_recalc),
271 CLKNODEMETHOD(clknode_set_freq, rk3328_clk_pll_set_freq),
275 DEFINE_CLASS_1(rk3328_clk_pll_clknode, rk3328_clk_pll_clknode_class,
276 rk3328_clk_pll_clknode_methods, sizeof(struct rk_clk_pll_sc), clknode_class);
279 rk3328_clk_pll_register(struct clkdom *clkdom, struct rk_clk_pll_def *clkdef)
282 struct rk_clk_pll_sc *sc;
284 clk = clknode_create(clkdom, &rk3328_clk_pll_clknode_class,
289 sc = clknode_get_softc(clk);
291 sc->base_offset = clkdef->base_offset;
292 sc->gate_offset = clkdef->gate_offset;
293 sc->gate_shift = clkdef->gate_shift;
294 sc->mode_reg = clkdef->mode_reg;
295 sc->mode_shift = clkdef->mode_shift;
296 sc->flags = clkdef->flags;
297 sc->rates = clkdef->rates;
298 sc->frac_rates = clkdef->frac_rates;
300 clknode_register(clkdom, clk);
305 #define RK3399_CLK_PLL_FBDIV_OFFSET 0
306 #define RK3399_CLK_PLL_FBDIV_SHIFT 0
307 #define RK3399_CLK_PLL_FBDIV_MASK 0xFFF
309 #define RK3399_CLK_PLL_POSTDIV2_OFFSET 4
310 #define RK3399_CLK_PLL_POSTDIV2_SHIFT 12
311 #define RK3399_CLK_PLL_POSTDIV2_MASK 0x7000
313 #define RK3399_CLK_PLL_POSTDIV1_OFFSET 4
314 #define RK3399_CLK_PLL_POSTDIV1_SHIFT 8
315 #define RK3399_CLK_PLL_POSTDIV1_MASK 0x700
317 #define RK3399_CLK_PLL_REFDIV_OFFSET 4
318 #define RK3399_CLK_PLL_REFDIV_SHIFT 0
319 #define RK3399_CLK_PLL_REFDIV_MASK 0x3F
321 #define RK3399_CLK_PLL_FRAC_OFFSET 8
322 #define RK3399_CLK_PLL_FRAC_SHIFT 0
323 #define RK3399_CLK_PLL_FRAC_MASK 0xFFFFFF
325 #define RK3399_CLK_PLL_DSMPD_OFFSET 0xC
326 #define RK3399_CLK_PLL_DSMPD_SHIFT 3
327 #define RK3399_CLK_PLL_DSMPD_MASK 0x8
329 #define RK3399_CLK_PLL_LOCK_OFFSET 8
330 #define RK3399_CLK_PLL_LOCK_MASK 0x400
332 #define RK3399_CLK_PLL_MODE_OFFSET 0xC
333 #define RK3399_CLK_PLL_MODE_MASK 0x300
334 #define RK3399_CLK_PLL_MODE_SLOW 0
335 #define RK3399_CLK_PLL_MODE_NORMAL 1
336 #define RK3399_CLK_PLL_MODE_DEEPSLOW 2
337 #define RK3399_CLK_PLL_MODE_SHIFT 8
339 #define RK3399_CLK_PLL_WRITE_MASK 0xFFFF0000
342 rk3399_clk_pll_init(struct clknode *clk, device_t dev)
344 struct rk_clk_pll_sc *sc;
347 sc = clknode_get_softc(clk);
349 if (sc->normal_mode) {
350 /* Setting to normal mode */
351 reg = RK3399_CLK_PLL_MODE_NORMAL << RK3399_CLK_PLL_MODE_SHIFT;
352 reg |= RK3399_CLK_PLL_MODE_MASK << RK_CLK_PLL_MASK_SHIFT;
353 WRITE4(clk, sc->base_offset + RK3399_CLK_PLL_MODE_OFFSET,
354 reg | RK3399_CLK_PLL_WRITE_MASK);
357 clknode_init_parent_idx(clk, 0);
363 rk3399_clk_pll_recalc(struct clknode *clk, uint64_t *freq)
365 struct rk_clk_pll_sc *sc;
366 uint32_t dsmpd, refdiv, fbdiv;
367 uint32_t postdiv1, postdiv2, fracdiv;
368 uint32_t con1, con2, con3, con4;
371 sc = clknode_get_softc(clk);
374 READ4(clk, sc->base_offset, &con1);
375 READ4(clk, sc->base_offset + 4, &con2);
376 READ4(clk, sc->base_offset + 8, &con3);
377 READ4(clk, sc->base_offset + 0xC, &con4);
381 * if we are in slow mode the output freq
382 * is the parent one, the 24Mhz external oscillator
383 * if we are in deep mode the output freq is 32.768khz
385 mode = (con4 & RK3399_CLK_PLL_MODE_MASK) >> RK3399_CLK_PLL_MODE_SHIFT;
386 if (mode == RK3399_CLK_PLL_MODE_SLOW) {
387 dprintf("pll in slow mode, con4=%x\n", con4);
389 } else if (mode == RK3399_CLK_PLL_MODE_DEEPSLOW) {
390 dprintf("pll in deep slow, con4=%x\n", con4);
395 dprintf("con0: %x\n", con1);
396 dprintf("con1: %x\n", con2);
397 dprintf("con2: %x\n", con3);
398 dprintf("con3: %x\n", con4);
400 fbdiv = (con1 & RK3399_CLK_PLL_FBDIV_MASK) >> RK3399_CLK_PLL_FBDIV_SHIFT;
402 postdiv1 = (con2 & RK3399_CLK_PLL_POSTDIV1_MASK) >> RK3399_CLK_PLL_POSTDIV1_SHIFT;
403 postdiv2 = (con2 & RK3399_CLK_PLL_POSTDIV2_MASK) >> RK3399_CLK_PLL_POSTDIV2_SHIFT;
404 refdiv = (con2 & RK3399_CLK_PLL_REFDIV_MASK) >> RK3399_CLK_PLL_REFDIV_SHIFT;
406 fracdiv = (con3 & RK3399_CLK_PLL_FRAC_MASK) >> RK3399_CLK_PLL_FRAC_SHIFT;
409 dsmpd = (con4 & RK3399_CLK_PLL_DSMPD_MASK) >> RK3399_CLK_PLL_DSMPD_SHIFT;
411 dprintf("fbdiv: %d\n", fbdiv);
412 dprintf("postdiv1: %d\n", postdiv1);
413 dprintf("postdiv2: %d\n", postdiv2);
414 dprintf("refdiv: %d\n", refdiv);
415 dprintf("fracdiv: %d\n", fracdiv);
416 dprintf("dsmpd: %d\n", dsmpd);
418 dprintf("parent freq=%lu\n", *freq);
421 /* Fractional mode */
422 foutvco = *freq / refdiv * (fbdiv + fracdiv);
425 foutvco = *freq / refdiv * fbdiv;
427 dprintf("foutvco: %lu\n", foutvco);
429 *freq = foutvco / postdiv1 / postdiv2;
430 dprintf("freq: %lu\n", *freq);
436 rk3399_clk_pll_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout,
437 int flags, int *stop)
439 struct rk_clk_pll_rate *rates;
440 struct rk_clk_pll_sc *sc;
444 sc = clknode_get_softc(clk);
448 else if (sc->frac_rates)
449 rates = sc->frac_rates;
453 for (; rates->freq; rates++) {
454 if (rates->freq == *fout)
457 if (rates->freq == 0) {
464 /* Set to slow mode during frequency change */
465 reg = RK3399_CLK_PLL_MODE_SLOW << RK3399_CLK_PLL_MODE_SHIFT;
466 reg |= RK3399_CLK_PLL_MODE_MASK << RK_CLK_PLL_MASK_SHIFT;
467 WRITE4(clk, sc->base_offset + 0xC, reg);
470 reg = rates->fbdiv << RK3399_CLK_PLL_FBDIV_SHIFT;
471 reg |= RK3399_CLK_PLL_FBDIV_MASK << RK_CLK_PLL_MASK_SHIFT;
472 WRITE4(clk, sc->base_offset, reg);
474 /* Setting postdiv1, postdiv2 and refdiv */
475 reg = rates->postdiv1 << RK3399_CLK_PLL_POSTDIV1_SHIFT;
476 reg |= rates->postdiv2 << RK3399_CLK_PLL_POSTDIV2_SHIFT;
477 reg |= rates->refdiv << RK3399_CLK_PLL_REFDIV_SHIFT;
478 reg |= (RK3399_CLK_PLL_POSTDIV1_MASK | RK3399_CLK_PLL_POSTDIV2_MASK |
479 RK3399_CLK_PLL_REFDIV_MASK) << RK_CLK_PLL_MASK_SHIFT;
480 WRITE4(clk, sc->base_offset + 0x4, reg);
483 READ4(clk, sc->base_offset + 0x8, ®);
484 reg &= ~RK3399_CLK_PLL_FRAC_MASK;
485 reg |= rates->frac << RK3399_CLK_PLL_FRAC_SHIFT;
486 WRITE4(clk, sc->base_offset + 0x8, reg | RK3399_CLK_PLL_WRITE_MASK);
489 reg = rates->dsmpd << RK3399_CLK_PLL_DSMPD_SHIFT;
490 reg |= RK3399_CLK_PLL_DSMPD_MASK << RK_CLK_PLL_MASK_SHIFT;
491 WRITE4(clk, sc->base_offset + 0xC, reg);
494 for (timeout = 1000; timeout; timeout--) {
495 READ4(clk, sc->base_offset + RK3399_CLK_PLL_LOCK_OFFSET, ®);
496 if ((reg & RK3399_CLK_PLL_LOCK_MASK) == 0)
501 /* Set back to normal mode */
502 reg = RK3399_CLK_PLL_MODE_NORMAL << RK3399_CLK_PLL_MODE_SHIFT;
503 reg |= RK3399_CLK_PLL_MODE_MASK << RK_CLK_PLL_MASK_SHIFT;
504 WRITE4(clk, sc->base_offset + 0xC, reg);
512 static clknode_method_t rk3399_clk_pll_clknode_methods[] = {
513 /* Device interface */
514 CLKNODEMETHOD(clknode_init, rk3399_clk_pll_init),
515 CLKNODEMETHOD(clknode_set_gate, rk_clk_pll_set_gate),
516 CLKNODEMETHOD(clknode_recalc_freq, rk3399_clk_pll_recalc),
517 CLKNODEMETHOD(clknode_set_freq, rk3399_clk_pll_set_freq),
521 DEFINE_CLASS_1(rk3399_clk_pll_clknode, rk3399_clk_pll_clknode_class,
522 rk3399_clk_pll_clknode_methods, sizeof(struct rk_clk_pll_sc), clknode_class);
525 rk3399_clk_pll_register(struct clkdom *clkdom, struct rk_clk_pll_def *clkdef)
528 struct rk_clk_pll_sc *sc;
530 clk = clknode_create(clkdom, &rk3399_clk_pll_clknode_class,
535 sc = clknode_get_softc(clk);
537 sc->base_offset = clkdef->base_offset;
538 sc->gate_offset = clkdef->gate_offset;
539 sc->gate_shift = clkdef->gate_shift;
540 sc->flags = clkdef->flags;
541 sc->rates = clkdef->rates;
542 sc->frac_rates = clkdef->frac_rates;
543 sc->normal_mode = clkdef->normal_mode;
545 clknode_register(clkdom, clk);