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