]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm64/rockchip/clk/rk_clk_pll.c
arm64: rockchip: rk_clk_pll: Check mode on recalc
[FreeBSD/FreeBSD.git] / sys / arm64 / rockchip / clk / rk_clk_pll.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2018 Emmanuel Vadot <manu@freebsd.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
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.
15  *
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
26  * SUCH DAMAGE.
27  *
28  * $FreeBSD$
29  */
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/bus.h>
37
38 #include <dev/extres/clk/clk.h>
39
40 #include <arm64/rockchip/clk/rk_clk_pll.h>
41
42 #include "clkdev_if.h"
43
44 struct rk_clk_pll_sc {
45         uint32_t        base_offset;
46
47         uint32_t        gate_offset;
48         uint32_t        gate_shift;
49
50         uint32_t        mode_reg;
51         uint32_t        mode_shift;
52
53         uint32_t        flags;
54
55         struct rk_clk_pll_rate  *rates;
56         struct rk_clk_pll_rate  *frac_rates;
57
58         bool                    normal_mode;
59 };
60
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))
69
70 #define RK_CLK_PLL_MASK_SHIFT   16
71
72 /* #define      dprintf(format, arg...) printf("%s:(%s)" format, __func__, clknode_get_name(clk), arg) */
73 #define dprintf(format, arg...)
74
75 static int
76 rk_clk_pll_set_gate(struct clknode *clk, bool enable)
77 {
78         struct rk_clk_pll_sc *sc;
79         uint32_t val = 0;
80
81         sc = clknode_get_softc(clk);
82
83         if ((sc->flags & RK_CLK_PLL_HAVE_GATE) == 0)
84                 return (0);
85
86         dprintf("%sabling gate\n", enable ? "En" : "Dis");
87         if (!enable)
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);
92         DEVICE_LOCK(clk);
93         WRITE4(clk, sc->gate_offset, val);
94         DEVICE_UNLOCK(clk);
95
96         return (0);
97 }
98
99 #define RK3328_CLK_PLL_FBDIV_OFFSET     0
100 #define RK3328_CLK_PLL_FBDIV_SHIFT      0
101 #define RK3328_CLK_PLL_FBDIV_MASK       0xFFF
102
103 #define RK3328_CLK_PLL_POSTDIV1_OFFSET  0
104 #define RK3328_CLK_PLL_POSTDIV1_SHIFT   12
105 #define RK3328_CLK_PLL_POSTDIV1_MASK    0x7000
106
107 #define RK3328_CLK_PLL_DSMPD_OFFSET     4
108 #define RK3328_CLK_PLL_DSMPD_SHIFT      12
109 #define RK3328_CLK_PLL_DSMPD_MASK       0x1000
110
111 #define RK3328_CLK_PLL_REFDIV_OFFSET    4
112 #define RK3328_CLK_PLL_REFDIV_SHIFT     0
113 #define RK3328_CLK_PLL_REFDIV_MASK      0x3F
114
115 #define RK3328_CLK_PLL_POSTDIV2_OFFSET  4
116 #define RK3328_CLK_PLL_POSTDIV2_SHIFT   6
117 #define RK3328_CLK_PLL_POSTDIV2_MASK    0x1C0
118
119 #define RK3328_CLK_PLL_FRAC_OFFSET      8
120 #define RK3328_CLK_PLL_FRAC_SHIFT       0
121 #define RK3328_CLK_PLL_FRAC_MASK        0xFFFFFF
122
123 #define RK3328_CLK_PLL_LOCK_MASK        0x400
124
125 #define RK3328_CLK_PLL_MODE_SLOW        0
126 #define RK3328_CLK_PLL_MODE_NORMAL      1
127 #define RK3328_CLK_PLL_MODE_MASK        0x1
128
129 static int
130 rk3328_clk_pll_init(struct clknode *clk, device_t dev)
131 {
132         struct rk_clk_pll_sc *sc;
133
134         sc = clknode_get_softc(clk);
135
136         clknode_init_parent_idx(clk, 0);
137
138         return (0);
139 }
140
141 static int
142 rk3328_clk_pll_recalc(struct clknode *clk, uint64_t *freq)
143 {
144         struct rk_clk_pll_sc *sc;
145         uint64_t rate;
146         uint32_t dsmpd, refdiv, fbdiv;
147         uint32_t postdiv1, postdiv2, frac;
148         uint32_t raw1, raw2, raw3;
149
150         sc = clknode_get_softc(clk);
151
152         DEVICE_LOCK(clk);
153
154         READ4(clk, sc->base_offset, &raw1);
155         READ4(clk, sc->base_offset + 4, &raw2);
156         READ4(clk, sc->base_offset + 8, &raw3);
157
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;
160
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;
164
165         frac = (raw3 & RK3328_CLK_PLL_FRAC_MASK) >> RK3328_CLK_PLL_FRAC_SHIFT;
166
167         DEVICE_UNLOCK(clk);
168
169         rate = *freq * fbdiv / refdiv;
170         if (dsmpd == 0) {
171                 /* Fractional mode */
172                 uint64_t frac_rate;
173
174                 frac_rate = *freq * frac / refdiv;
175                 rate += frac_rate >> 24;
176         }
177
178         *freq = rate / postdiv1 / postdiv2;
179
180         if (*freq % 2)
181                 *freq = *freq + 1;
182
183         return (0);
184 }
185
186 static int
187 rk3328_clk_pll_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout,
188     int flags, int *stop)
189 {
190         struct rk_clk_pll_rate *rates;
191         struct rk_clk_pll_sc *sc;
192         uint32_t reg;
193         int timeout;
194
195         sc = clknode_get_softc(clk);
196
197         if (sc->rates)
198                 rates = sc->rates;
199         else if (sc->frac_rates)
200                 rates = sc->frac_rates;
201         else
202                 return (EINVAL);
203
204         for (; rates->freq; rates++) {
205                 if (rates->freq == *fout)
206                         break;
207         }
208         if (rates->freq == 0) {
209                 *stop = 1;
210                 return (EINVAL);
211         }
212
213         DEVICE_LOCK(clk);
214
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);
220
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);
227
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);
237
238         /* Setting frac */
239         READ4(clk, sc->base_offset + 0x8, &reg);
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);
244
245         /* Reading lock */
246         for (timeout = 1000; timeout; timeout--) {
247                 READ4(clk, sc->base_offset + 0x4, &reg);
248                 if ((reg & RK3328_CLK_PLL_LOCK_MASK) == 0)
249                         break;
250                 DELAY(1);
251         }
252
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);
259
260         DEVICE_UNLOCK(clk);
261
262         *stop = 1;
263         return (0);
264 }
265
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),
272         CLKNODEMETHOD_END
273 };
274
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);
277
278 int
279 rk3328_clk_pll_register(struct clkdom *clkdom, struct rk_clk_pll_def *clkdef)
280 {
281         struct clknode *clk;
282         struct rk_clk_pll_sc *sc;
283
284         clk = clknode_create(clkdom, &rk3328_clk_pll_clknode_class,
285             &clkdef->clkdef);
286         if (clk == NULL)
287                 return (1);
288
289         sc = clknode_get_softc(clk);
290
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;
299
300         clknode_register(clkdom, clk);
301
302         return (0);
303 }
304
305 #define RK3399_CLK_PLL_FBDIV_OFFSET             0
306 #define RK3399_CLK_PLL_FBDIV_SHIFT              0
307 #define RK3399_CLK_PLL_FBDIV_MASK               0xFFF
308
309 #define RK3399_CLK_PLL_POSTDIV2_OFFSET  4
310 #define RK3399_CLK_PLL_POSTDIV2_SHIFT   12
311 #define RK3399_CLK_PLL_POSTDIV2_MASK    0x7000
312
313 #define RK3399_CLK_PLL_POSTDIV1_OFFSET  4
314 #define RK3399_CLK_PLL_POSTDIV1_SHIFT   8
315 #define RK3399_CLK_PLL_POSTDIV1_MASK    0x700
316
317 #define RK3399_CLK_PLL_REFDIV_OFFSET    4
318 #define RK3399_CLK_PLL_REFDIV_SHIFT     0
319 #define RK3399_CLK_PLL_REFDIV_MASK      0x3F
320
321 #define RK3399_CLK_PLL_FRAC_OFFSET      8
322 #define RK3399_CLK_PLL_FRAC_SHIFT       0
323 #define RK3399_CLK_PLL_FRAC_MASK        0xFFFFFF
324
325 #define RK3399_CLK_PLL_DSMPD_OFFSET     0xC
326 #define RK3399_CLK_PLL_DSMPD_SHIFT      3
327 #define RK3399_CLK_PLL_DSMPD_MASK       0x8
328
329 #define RK3399_CLK_PLL_LOCK_OFFSET      8
330 #define RK3399_CLK_PLL_LOCK_MASK        0x400
331
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
338
339 #define RK3399_CLK_PLL_WRITE_MASK       0xFFFF0000
340
341 static int
342 rk3399_clk_pll_init(struct clknode *clk, device_t dev)
343 {
344         struct rk_clk_pll_sc *sc;
345         uint32_t reg;
346
347         sc = clknode_get_softc(clk);
348
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);
355         }
356
357         clknode_init_parent_idx(clk, 0);
358
359         return (0);
360 }
361
362 static int
363 rk3399_clk_pll_recalc(struct clknode *clk, uint64_t *freq)
364 {
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;
369         uint64_t foutvco;
370         uint32_t mode;
371         sc = clknode_get_softc(clk);
372
373         DEVICE_LOCK(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);
378         DEVICE_UNLOCK(clk);
379
380         /*
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
384          */
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);
388                 return (0);
389         } else if (mode == RK3399_CLK_PLL_MODE_DEEPSLOW) {
390                 dprintf("pll in deep slow, con4=%x\n", con4);
391                 *freq = 32768;
392                 return (0);
393         }
394
395         dprintf("con0: %x\n", con1);
396         dprintf("con1: %x\n", con2);
397         dprintf("con2: %x\n", con3);
398         dprintf("con3: %x\n", con4);
399
400         fbdiv = (con1 & RK3399_CLK_PLL_FBDIV_MASK) >> RK3399_CLK_PLL_FBDIV_SHIFT;
401
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;
405
406         fracdiv = (con3 & RK3399_CLK_PLL_FRAC_MASK) >> RK3399_CLK_PLL_FRAC_SHIFT;
407         fracdiv >>= 24;
408
409         dsmpd = (con4 & RK3399_CLK_PLL_DSMPD_MASK) >> RK3399_CLK_PLL_DSMPD_SHIFT;
410
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);
417
418         dprintf("parent freq=%lu\n", *freq);
419
420         if (dsmpd == 0) {
421                 /* Fractional mode */
422                 foutvco = *freq / refdiv * (fbdiv + fracdiv);
423         } else {
424                 /* Integer mode */
425                 foutvco = *freq / refdiv * fbdiv;
426         }
427         dprintf("foutvco: %lu\n", foutvco);
428
429         *freq = foutvco / postdiv1 / postdiv2;
430         dprintf("freq: %lu\n", *freq);
431
432         return (0);
433 }
434
435 static int
436 rk3399_clk_pll_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout,
437     int flags, int *stop)
438 {
439         struct rk_clk_pll_rate *rates;
440         struct rk_clk_pll_sc *sc;
441         uint32_t reg;
442         int timeout;
443
444         sc = clknode_get_softc(clk);
445
446         if (sc->rates)
447                 rates = sc->rates;
448         else if (sc->frac_rates)
449                 rates = sc->frac_rates;
450         else
451                 return (EINVAL);
452
453         for (; rates->freq; rates++) {
454                 if (rates->freq == *fout)
455                         break;
456         }
457         if (rates->freq == 0) {
458                 *stop = 1;
459                 return (EINVAL);
460         }
461
462         DEVICE_LOCK(clk);
463
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);
468
469         /* Setting fbdiv */
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);
473
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);
481
482         /* Setting frac */
483         READ4(clk, sc->base_offset + 0x8, &reg);
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);
487
488         /* Set dsmpd */
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);
492
493         /* Reading lock */
494         for (timeout = 1000; timeout; timeout--) {
495                 READ4(clk, sc->base_offset + RK3399_CLK_PLL_LOCK_OFFSET, &reg);
496                 if ((reg & RK3399_CLK_PLL_LOCK_MASK) == 0)
497                         break;
498                 DELAY(1);
499         }
500
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);
505
506         DEVICE_UNLOCK(clk);
507
508         *stop = 1;
509         return (0);
510 }
511
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),
518         CLKNODEMETHOD_END
519 };
520
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);
523
524 int
525 rk3399_clk_pll_register(struct clkdom *clkdom, struct rk_clk_pll_def *clkdef)
526 {
527         struct clknode *clk;
528         struct rk_clk_pll_sc *sc;
529
530         clk = clknode_create(clkdom, &rk3399_clk_pll_clknode_class,
531             &clkdef->clkdef);
532         if (clk == NULL)
533                 return (1);
534
535         sc = clknode_get_softc(clk);
536
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;
544
545         clknode_register(clkdom, clk);
546
547         return (0);
548 }