2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2018 Emmanuel Vadot <manu@freebsd.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
33 #include <sys/param.h>
34 #include <sys/systm.h>
37 #include <dev/extres/clk/clk.h>
39 #include <arm64/rockchip/clk/rk_clk_pll.h>
41 #include "clkdev_if.h"
43 struct rk_clk_pll_sc {
54 struct rk_clk_pll_rate *rates;
55 struct rk_clk_pll_rate *frac_rates;
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))
67 #define RK_CLK_PLL_MASK_SHIFT 16
70 #define dprintf(format, arg...) \
71 printf("%s:(%s)" format, __func__, clknode_get_name(clk), arg)
73 #define dprintf(format, arg...)
77 rk_clk_pll_set_gate(struct clknode *clk, bool enable)
79 struct rk_clk_pll_sc *sc;
82 sc = clknode_get_softc(clk);
84 if ((sc->flags & RK_CLK_PLL_HAVE_GATE) == 0)
87 dprintf("%sabling gate\n", enable ? "En" : "Dis");
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);
94 WRITE4(clk, sc->gate_offset, val);
100 #define RK3328_CLK_PLL_FBDIV_OFFSET 0
101 #define RK3328_CLK_PLL_FBDIV_SHIFT 0
102 #define RK3328_CLK_PLL_FBDIV_MASK 0xFFF
104 #define RK3328_CLK_PLL_POSTDIV1_OFFSET 0
105 #define RK3328_CLK_PLL_POSTDIV1_SHIFT 12
106 #define RK3328_CLK_PLL_POSTDIV1_MASK 0x7000
108 #define RK3328_CLK_PLL_DSMPD_OFFSET 4
109 #define RK3328_CLK_PLL_DSMPD_SHIFT 12
110 #define RK3328_CLK_PLL_DSMPD_MASK 0x1000
112 #define RK3328_CLK_PLL_REFDIV_OFFSET 4
113 #define RK3328_CLK_PLL_REFDIV_SHIFT 0
114 #define RK3328_CLK_PLL_REFDIV_MASK 0x3F
116 #define RK3328_CLK_PLL_POSTDIV2_OFFSET 4
117 #define RK3328_CLK_PLL_POSTDIV2_SHIFT 6
118 #define RK3328_CLK_PLL_POSTDIV2_MASK 0x1C0
120 #define RK3328_CLK_PLL_FRAC_OFFSET 8
121 #define RK3328_CLK_PLL_FRAC_SHIFT 0
122 #define RK3328_CLK_PLL_FRAC_MASK 0xFFFFFF
124 #define RK3328_CLK_PLL_LOCK_MASK 0x400
126 #define RK3328_CLK_PLL_MODE_SLOW 0
127 #define RK3328_CLK_PLL_MODE_NORMAL 1
128 #define RK3328_CLK_PLL_MODE_MASK 0x1
131 rk3328_clk_pll_init(struct clknode *clk, device_t dev)
133 struct rk_clk_pll_sc *sc;
135 sc = clknode_get_softc(clk);
137 clknode_init_parent_idx(clk, 0);
143 rk3328_clk_pll_recalc(struct clknode *clk, uint64_t *freq)
145 struct rk_clk_pll_sc *sc;
147 uint32_t dsmpd, refdiv, fbdiv;
148 uint32_t postdiv1, postdiv2, frac;
149 uint32_t raw1, raw2, raw3;
151 sc = clknode_get_softc(clk);
155 READ4(clk, sc->base_offset, &raw1);
156 READ4(clk, sc->base_offset + 4, &raw2);
157 READ4(clk, sc->base_offset + 8, &raw3);
159 fbdiv = (raw1 & RK3328_CLK_PLL_FBDIV_MASK) >> RK3328_CLK_PLL_FBDIV_SHIFT;
160 postdiv1 = (raw1 & RK3328_CLK_PLL_POSTDIV1_MASK) >> RK3328_CLK_PLL_POSTDIV1_SHIFT;
162 dsmpd = (raw2 & RK3328_CLK_PLL_DSMPD_MASK) >> RK3328_CLK_PLL_DSMPD_SHIFT;
163 refdiv = (raw2 & RK3328_CLK_PLL_REFDIV_MASK) >> RK3328_CLK_PLL_REFDIV_SHIFT;
164 postdiv2 = (raw2 & RK3328_CLK_PLL_POSTDIV2_MASK) >> RK3328_CLK_PLL_POSTDIV2_SHIFT;
166 frac = (raw3 & RK3328_CLK_PLL_FRAC_MASK) >> RK3328_CLK_PLL_FRAC_SHIFT;
170 rate = *freq * fbdiv / refdiv;
172 /* Fractional mode */
175 frac_rate = *freq * frac / refdiv;
176 rate += frac_rate >> 24;
179 *freq = rate / postdiv1 / postdiv2;
188 rk3328_clk_pll_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout,
189 int flags, int *stop)
191 struct rk_clk_pll_rate *rates;
192 struct rk_clk_pll_sc *sc;
196 sc = clknode_get_softc(clk);
200 else if (sc->frac_rates)
201 rates = sc->frac_rates;
205 for (; rates->freq; rates++) {
206 if (rates->freq == *fout)
209 if (rates->freq == 0) {
216 /* Setting to slow mode during frequency change */
217 reg = (RK3328_CLK_PLL_MODE_MASK << sc->mode_shift) <<
218 RK_CLK_PLL_MASK_SHIFT;
219 dprintf("Set PLL_MODEREG to %x\n", reg);
220 WRITE4(clk, sc->mode_reg, reg);
222 /* Setting postdiv1 and fbdiv */
223 reg = (rates->postdiv1 << RK3328_CLK_PLL_POSTDIV1_SHIFT) |
224 (rates->fbdiv << RK3328_CLK_PLL_FBDIV_SHIFT);
225 reg |= (RK3328_CLK_PLL_POSTDIV1_MASK | RK3328_CLK_PLL_FBDIV_MASK) << 16;
226 dprintf("Set PLL_CON0 to %x\n", reg);
227 WRITE4(clk, sc->base_offset, reg);
229 /* Setting dsmpd, postdiv2 and refdiv */
230 reg = (rates->dsmpd << RK3328_CLK_PLL_DSMPD_SHIFT) |
231 (rates->postdiv2 << RK3328_CLK_PLL_POSTDIV2_SHIFT) |
232 (rates->refdiv << RK3328_CLK_PLL_REFDIV_SHIFT);
233 reg |= (RK3328_CLK_PLL_DSMPD_MASK |
234 RK3328_CLK_PLL_POSTDIV2_MASK |
235 RK3328_CLK_PLL_REFDIV_MASK) << RK_CLK_PLL_MASK_SHIFT;
236 dprintf("Set PLL_CON1 to %x\n", reg);
237 WRITE4(clk, sc->base_offset + 0x4, reg);
240 READ4(clk, sc->base_offset + 0x8, ®);
241 reg &= ~RK3328_CLK_PLL_FRAC_MASK;
242 reg |= rates->frac << RK3328_CLK_PLL_FRAC_SHIFT;
243 dprintf("Set PLL_CON2 to %x\n", reg);
244 WRITE4(clk, sc->base_offset + 0x8, reg);
247 for (timeout = 1000; timeout; timeout--) {
248 READ4(clk, sc->base_offset + 0x4, ®);
249 if ((reg & RK3328_CLK_PLL_LOCK_MASK) == 0)
254 /* Set back to normal mode */
255 reg = (RK3328_CLK_PLL_MODE_NORMAL << sc->mode_shift);
256 reg |= (RK3328_CLK_PLL_MODE_MASK << sc->mode_shift) <<
257 RK_CLK_PLL_MASK_SHIFT;
258 dprintf("Set PLL_MODEREG to %x\n", reg);
259 WRITE4(clk, sc->mode_reg, reg);
267 static clknode_method_t rk3328_clk_pll_clknode_methods[] = {
268 /* Device interface */
269 CLKNODEMETHOD(clknode_init, rk3328_clk_pll_init),
270 CLKNODEMETHOD(clknode_set_gate, rk_clk_pll_set_gate),
271 CLKNODEMETHOD(clknode_recalc_freq, rk3328_clk_pll_recalc),
272 CLKNODEMETHOD(clknode_set_freq, rk3328_clk_pll_set_freq),
276 DEFINE_CLASS_1(rk3328_clk_pll_clknode, rk3328_clk_pll_clknode_class,
277 rk3328_clk_pll_clknode_methods, sizeof(struct rk_clk_pll_sc), clknode_class);
280 rk3328_clk_pll_register(struct clkdom *clkdom, struct rk_clk_pll_def *clkdef)
283 struct rk_clk_pll_sc *sc;
285 clk = clknode_create(clkdom, &rk3328_clk_pll_clknode_class,
290 sc = clknode_get_softc(clk);
292 sc->base_offset = clkdef->base_offset;
293 sc->gate_offset = clkdef->gate_offset;
294 sc->gate_shift = clkdef->gate_shift;
295 sc->mode_reg = clkdef->mode_reg;
296 sc->mode_shift = clkdef->mode_shift;
297 sc->flags = clkdef->flags;
298 sc->rates = clkdef->rates;
299 sc->frac_rates = clkdef->frac_rates;
301 clknode_register(clkdom, clk);
306 #define RK3399_CLK_PLL_FBDIV_OFFSET 0
307 #define RK3399_CLK_PLL_FBDIV_SHIFT 0
308 #define RK3399_CLK_PLL_FBDIV_MASK 0xFFF
310 #define RK3399_CLK_PLL_POSTDIV2_OFFSET 4
311 #define RK3399_CLK_PLL_POSTDIV2_SHIFT 12
312 #define RK3399_CLK_PLL_POSTDIV2_MASK 0x7000
314 #define RK3399_CLK_PLL_POSTDIV1_OFFSET 4
315 #define RK3399_CLK_PLL_POSTDIV1_SHIFT 8
316 #define RK3399_CLK_PLL_POSTDIV1_MASK 0x700
318 #define RK3399_CLK_PLL_REFDIV_OFFSET 4
319 #define RK3399_CLK_PLL_REFDIV_SHIFT 0
320 #define RK3399_CLK_PLL_REFDIV_MASK 0x3F
322 #define RK3399_CLK_PLL_FRAC_OFFSET 8
323 #define RK3399_CLK_PLL_FRAC_SHIFT 0
324 #define RK3399_CLK_PLL_FRAC_MASK 0xFFFFFF
326 #define RK3399_CLK_PLL_DSMPD_OFFSET 0xC
327 #define RK3399_CLK_PLL_DSMPD_SHIFT 3
328 #define RK3399_CLK_PLL_DSMPD_MASK 0x8
330 #define RK3399_CLK_PLL_LOCK_OFFSET 8
331 #define RK3399_CLK_PLL_LOCK_MASK 0x400
333 #define RK3399_CLK_PLL_MODE_OFFSET 0xC
334 #define RK3399_CLK_PLL_MODE_MASK 0x300
335 #define RK3399_CLK_PLL_MODE_SLOW 0
336 #define RK3399_CLK_PLL_MODE_NORMAL 1
337 #define RK3399_CLK_PLL_MODE_DEEPSLOW 2
338 #define RK3399_CLK_PLL_MODE_SHIFT 8
340 #define RK3399_CLK_PLL_WRITE_MASK 0xFFFF0000
343 rk3399_clk_pll_init(struct clknode *clk, device_t dev)
345 struct rk_clk_pll_sc *sc;
347 sc = clknode_get_softc(clk);
348 clknode_init_parent_idx(clk, 0);
354 rk3399_clk_pll_recalc(struct clknode *clk, uint64_t *freq)
356 struct rk_clk_pll_sc *sc;
357 uint32_t dsmpd, refdiv, fbdiv;
358 uint32_t postdiv1, postdiv2, fracdiv;
359 uint32_t con1, con2, con3, con4;
362 sc = clknode_get_softc(clk);
365 READ4(clk, sc->base_offset, &con1);
366 READ4(clk, sc->base_offset + 4, &con2);
367 READ4(clk, sc->base_offset + 8, &con3);
368 READ4(clk, sc->base_offset + 0xC, &con4);
372 * if we are in slow mode the output freq
373 * is the parent one, the 24Mhz external oscillator
374 * if we are in deep mode the output freq is 32.768khz
376 mode = (con4 & RK3399_CLK_PLL_MODE_MASK) >> RK3399_CLK_PLL_MODE_SHIFT;
377 if (mode == RK3399_CLK_PLL_MODE_SLOW) {
378 dprintf("pll in slow mode, con4=%x\n", con4);
380 } else if (mode == RK3399_CLK_PLL_MODE_DEEPSLOW) {
381 dprintf("pll in deep slow, con4=%x\n", con4);
386 dprintf("con0: %x\n", con1);
387 dprintf("con1: %x\n", con2);
388 dprintf("con2: %x\n", con3);
389 dprintf("con3: %x\n", con4);
391 fbdiv = (con1 & RK3399_CLK_PLL_FBDIV_MASK)
392 >> RK3399_CLK_PLL_FBDIV_SHIFT;
394 postdiv1 = (con2 & RK3399_CLK_PLL_POSTDIV1_MASK)
395 >> RK3399_CLK_PLL_POSTDIV1_SHIFT;
396 postdiv2 = (con2 & RK3399_CLK_PLL_POSTDIV2_MASK)
397 >> RK3399_CLK_PLL_POSTDIV2_SHIFT;
398 refdiv = (con2 & RK3399_CLK_PLL_REFDIV_MASK)
399 >> RK3399_CLK_PLL_REFDIV_SHIFT;
401 fracdiv = (con3 & RK3399_CLK_PLL_FRAC_MASK)
402 >> RK3399_CLK_PLL_FRAC_SHIFT;
405 dsmpd = (con4 & RK3399_CLK_PLL_DSMPD_MASK) >> RK3399_CLK_PLL_DSMPD_SHIFT;
407 dprintf("fbdiv: %d\n", fbdiv);
408 dprintf("postdiv1: %d\n", postdiv1);
409 dprintf("postdiv2: %d\n", postdiv2);
410 dprintf("refdiv: %d\n", refdiv);
411 dprintf("fracdiv: %d\n", fracdiv);
412 dprintf("dsmpd: %d\n", dsmpd);
414 dprintf("parent freq=%ju\n", *freq);
417 /* Fractional mode */
418 foutvco = *freq / refdiv * (fbdiv + fracdiv);
421 foutvco = *freq / refdiv * fbdiv;
423 dprintf("foutvco: %ju\n", foutvco);
425 *freq = foutvco / postdiv1 / postdiv2;
426 dprintf("freq: %ju\n", *freq);
432 rk3399_clk_pll_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout,
433 int flags, int *stop)
435 struct rk_clk_pll_rate *rates;
436 struct rk_clk_pll_sc *sc;
440 sc = clknode_get_softc(clk);
444 else if (sc->frac_rates)
445 rates = sc->frac_rates;
449 for (; rates->freq; rates++) {
450 if (rates->freq == *fout)
453 if (rates->freq == 0) {
460 /* Set to slow mode during frequency change */
461 reg = RK3399_CLK_PLL_MODE_SLOW << RK3399_CLK_PLL_MODE_SHIFT;
462 reg |= RK3399_CLK_PLL_MODE_MASK << RK_CLK_PLL_MASK_SHIFT;
463 WRITE4(clk, sc->base_offset + 0xC, reg);
466 reg = rates->fbdiv << RK3399_CLK_PLL_FBDIV_SHIFT;
467 reg |= RK3399_CLK_PLL_FBDIV_MASK << RK_CLK_PLL_MASK_SHIFT;
468 WRITE4(clk, sc->base_offset, reg);
470 /* Setting postdiv1, postdiv2 and refdiv */
471 reg = rates->postdiv1 << RK3399_CLK_PLL_POSTDIV1_SHIFT;
472 reg |= rates->postdiv2 << RK3399_CLK_PLL_POSTDIV2_SHIFT;
473 reg |= rates->refdiv << RK3399_CLK_PLL_REFDIV_SHIFT;
474 reg |= (RK3399_CLK_PLL_POSTDIV1_MASK | RK3399_CLK_PLL_POSTDIV2_MASK |
475 RK3399_CLK_PLL_REFDIV_MASK) << RK_CLK_PLL_MASK_SHIFT;
476 WRITE4(clk, sc->base_offset + 0x4, reg);
479 READ4(clk, sc->base_offset + 0x8, ®);
480 reg &= ~RK3399_CLK_PLL_FRAC_MASK;
481 reg |= rates->frac << RK3399_CLK_PLL_FRAC_SHIFT;
482 WRITE4(clk, sc->base_offset + 0x8, reg | RK3399_CLK_PLL_WRITE_MASK);
485 reg = rates->dsmpd << RK3399_CLK_PLL_DSMPD_SHIFT;
486 reg |= RK3399_CLK_PLL_DSMPD_MASK << RK_CLK_PLL_MASK_SHIFT;
487 WRITE4(clk, sc->base_offset + 0xC, reg);
490 for (timeout = 1000; timeout; timeout--) {
491 READ4(clk, sc->base_offset + RK3399_CLK_PLL_LOCK_OFFSET, ®);
492 if ((reg & RK3399_CLK_PLL_LOCK_MASK) == 0)
497 /* Set back to normal mode */
498 reg = RK3399_CLK_PLL_MODE_NORMAL << RK3399_CLK_PLL_MODE_SHIFT;
499 reg |= RK3399_CLK_PLL_MODE_MASK << RK_CLK_PLL_MASK_SHIFT;
500 WRITE4(clk, sc->base_offset + 0xC, reg);
508 static clknode_method_t rk3399_clk_pll_clknode_methods[] = {
509 /* Device interface */
510 CLKNODEMETHOD(clknode_init, rk3399_clk_pll_init),
511 CLKNODEMETHOD(clknode_set_gate, rk_clk_pll_set_gate),
512 CLKNODEMETHOD(clknode_recalc_freq, rk3399_clk_pll_recalc),
513 CLKNODEMETHOD(clknode_set_freq, rk3399_clk_pll_set_freq),
517 DEFINE_CLASS_1(rk3399_clk_pll_clknode, rk3399_clk_pll_clknode_class,
518 rk3399_clk_pll_clknode_methods, sizeof(struct rk_clk_pll_sc), clknode_class);
521 rk3399_clk_pll_register(struct clkdom *clkdom, struct rk_clk_pll_def *clkdef)
524 struct rk_clk_pll_sc *sc;
526 clk = clknode_create(clkdom, &rk3399_clk_pll_clknode_class,
531 sc = clknode_get_softc(clk);
533 sc->base_offset = clkdef->base_offset;
534 sc->gate_offset = clkdef->gate_offset;
535 sc->gate_shift = clkdef->gate_shift;
536 sc->flags = clkdef->flags;
537 sc->rates = clkdef->rates;
538 sc->frac_rates = clkdef->frac_rates;
540 clknode_register(clkdom, clk);