1 /*-
2 * Copyright (c) 2017 Emmanuel Vadot <manu@freebsd.org>
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
18 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
20 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
21 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26 #ifndef __AW_CLK_H__
27 #define __AW_CLK_H__
28
29 /*
30 Allwinner clocks formula :
31
32 PLLs:
33
34 (24MHz*N*K)/(M*P)
35 (24MHz*N)/(M*P)
36 (24MHz*N*2)/M
37 (24MHz*N)/M
38 (24MHz*N*K)/M
39 (24MHz*N*K/2)
40 (24MHz*N)/M
41 (24MHz*N*K/2)
42 (24MHz*N)/M
43
44 Periph clocks:
45
46 Clock Source/Divider N/Divider M
47 Clock Source/Divider N/Divider M/2
48 Clock Source*N/(Divider M+1)/(Divider P+1)
49
50 */
51
52 struct aw_clk_init {
53 const char *name;
54 const char *parent_name;
55 uint64_t default_freq;
56 bool enable;
57 };
58
59 #define AW_CLK_HAS_GATE 0x0001
60 #define AW_CLK_HAS_LOCK 0x0002
61 #define AW_CLK_HAS_MUX 0x0004
62 #define AW_CLK_REPARENT 0x0008
63 #define AW_CLK_SCALE_CHANGE 0x0010
64 #define AW_CLK_HAS_UPDATE 0x0040
65 #define AW_CLK_HAS_PREDIV 0x0080
66 #define AW_CLK_SET_PARENT 0x0100
67
68 #define AW_CLK_FACTOR_POWER_OF_TWO 0x0001
69 #define AW_CLK_FACTOR_ZERO_BASED 0x0002
70 #define AW_CLK_FACTOR_HAS_COND 0x0004
71 #define AW_CLK_FACTOR_FIXED 0x0008
72 #define AW_CLK_FACTOR_ZERO_IS_ONE 0x0010
73 #define AW_CLK_FACTOR_MIN_VALUE 0x0020
74 #define AW_CLK_FACTOR_MAX_VALUE 0x0040
75
76 struct aw_clk_factor {
77 uint32_t shift; /* Shift bits for the factor */
78 uint32_t mask; /* Mask to get the factor, will be override by the clk methods */
79 uint32_t width; /* Number of bits for the factor */
80 uint32_t value; /* Fixed value, depends on AW_CLK_FACTOR_FIXED */
81
82 uint32_t cond_shift;
83 uint32_t cond_mask;
84 uint32_t cond_width;
85 uint32_t cond_value;
86
87 uint32_t min_value;
88 uint32_t max_value;
89
90 uint32_t flags; /* Flags */
91 };
92
93 struct aw_clk_frac {
94 uint64_t freq0;
95 uint64_t freq1;
96 uint32_t mode_sel;
97 uint32_t freq_sel;
98 };
99
100 static inline uint32_t
aw_clk_get_factor(uint32_t val,struct aw_clk_factor * factor)101 aw_clk_get_factor(uint32_t val, struct aw_clk_factor *factor)
102 {
103 uint32_t factor_val;
104 uint32_t cond;
105
106 if (factor->flags & AW_CLK_FACTOR_HAS_COND) {
107 cond = (val & factor->cond_mask) >> factor->cond_shift;
108 if (cond != factor->cond_value)
109 return (1);
110 }
111
112 if (factor->flags & AW_CLK_FACTOR_FIXED)
113 return (factor->value);
114
115 factor_val = (val & factor->mask) >> factor->shift;
116 if (factor_val == 0 && (factor->flags & AW_CLK_FACTOR_ZERO_IS_ONE))
117 factor_val = 1;
118
119 if (factor->flags & AW_CLK_FACTOR_POWER_OF_TWO)
120 factor_val = 1 << factor_val;
121 else if (!(factor->flags & AW_CLK_FACTOR_ZERO_BASED))
122 factor_val += 1;
123
124 return (factor_val);
125 }
126
127 static inline uint32_t
aw_clk_factor_get_max(struct aw_clk_factor * factor)128 aw_clk_factor_get_max(struct aw_clk_factor *factor)
129 {
130 uint32_t max;
131
132 if (factor->flags & AW_CLK_FACTOR_FIXED)
133 max = factor->value;
134 else if (factor->flags & AW_CLK_FACTOR_POWER_OF_TWO)
135 max = 1 << ((1 << factor->width) - 1);
136 else {
137 max = (1 << factor->width);
138 }
139
140 return (max);
141 }
142
143 static inline uint32_t
aw_clk_factor_get_min(struct aw_clk_factor * factor)144 aw_clk_factor_get_min(struct aw_clk_factor *factor)
145 {
146 uint32_t min;
147
148 if (factor->flags & AW_CLK_FACTOR_FIXED)
149 min = factor->value;
150 else if (factor->flags & AW_CLK_FACTOR_ZERO_BASED)
151 min = 0;
152 else if (factor->flags & AW_CLK_FACTOR_MIN_VALUE)
153 min = factor->min_value;
154 else
155 min = 1;
156
157 return (min);
158 }
159
160 static inline uint32_t
aw_clk_factor_get_value(struct aw_clk_factor * factor,uint32_t raw)161 aw_clk_factor_get_value(struct aw_clk_factor *factor, uint32_t raw)
162 {
163 uint32_t val;
164
165 if (factor->flags & AW_CLK_FACTOR_FIXED)
166 return (factor->value);
167
168 if (factor->flags & AW_CLK_FACTOR_ZERO_BASED)
169 val = raw;
170 else if (factor->flags & AW_CLK_FACTOR_POWER_OF_TWO) {
171 for (val = 0; raw != 1; val++)
172 raw >>= 1;
173 } else if (factor->flags & AW_CLK_FACTOR_MAX_VALUE)
174 val = factor->max_value;
175 else
176 val = raw - 1;
177
178 return (val);
179 }
180
181 #define CCU_RESET(idx, o, s) \
182 [idx] = { \
183 .offset = o, \
184 .shift = s, \
185 },
186
187 #define CCU_GATE(idx, clkname, pname, o, s) \
188 [idx] = { \
189 .name = clkname, \
190 .parent_name = pname, \
191 .offset = o, \
192 .shift = s, \
193 },
194
195 #define NKMP_CLK(_clkname, _id, _name, _pnames, \
196 _offset, \
197 _n_shift, _n_width, _n_value, _n_flags, \
198 _k_shift, _k_width, _k_value, _k_flags, \
199 _m_shift, _m_width, _m_value, _m_flags, \
200 _p_shift, _p_width, _p_value, _p_flags, \
201 _gate, \
202 _lock, _lock_retries, \
203 _flags) \
204 static struct aw_clk_nkmp_def _clkname = { \
205 .clkdef = { \
206 .id = _id, \
207 .name = _name, \
208 .parent_names = _pnames, \
209 .parent_cnt = nitems(_pnames), \
210 }, \
211 .offset = _offset, \
212 .n.shift = _n_shift, \
213 .n.width = _n_width, \
214 .n.value = _n_value, \
215 .n.flags = _n_flags, \
216 .k.shift = _k_shift, \
217 .k.width = _k_width, \
218 .k.value = _k_value, \
219 .k.flags = _k_flags, \
220 .m.shift = _m_shift, \
221 .m.width = _m_width, \
222 .m.value = _m_value, \
223 .m.flags = _m_flags, \
224 .p.shift = _p_shift, \
225 .p.width = _p_width, \
226 .p.value = _p_value, \
227 .p.flags = _p_flags, \
228 .gate_shift = _gate, \
229 .lock_shift = _lock, \
230 .lock_retries = _lock_retries, \
231 .flags = _flags, \
232 }
233
234 #define NKMP_CLK_WITH_MUX(_clkname, \
235 _id, _name, _pnames, \
236 _offset, \
237 _n_shift, _n_width, _n_value, _n_flags, \
238 _k_shift, _k_width, _k_value, _k_flags, \
239 _m_shift, _m_width, _m_value, _m_flags, \
240 _p_shift, _p_width, _p_value, _p_flags, \
241 _mux_shift, _mux_width, _gate, \
242 _lock, _lock_retries, \
243 _flags) \
244 static struct aw_clk_nkmp_def _clkname = { \
245 .clkdef = { \
246 .id = _id, \
247 .name = _name, \
248 .parent_names = _pnames, \
249 .parent_cnt = nitems(_pnames), \
250 }, \
251 .offset = _offset, \
252 .n.shift = _n_shift, \
253 .n.width = _n_width, \
254 .n.value = _n_value, \
255 .n.flags = _n_flags, \
256 .k.shift = _k_shift, \
257 .k.width = _k_width, \
258 .k.value = _k_value, \
259 .k.flags = _k_flags, \
260 .m.shift = _m_shift, \
261 .m.width = _m_width, \
262 .m.value = _m_value, \
263 .m.flags = _m_flags, \
264 .p.shift = _p_shift, \
265 .p.width = _p_width, \
266 .p.value = _p_value, \
267 .p.flags = _p_flags, \
268 .mux_shift = _mux_shift, \
269 .mux_width = _mux_width, \
270 .gate_shift = _gate, \
271 .lock_shift = _lock, \
272 .lock_retries = _lock_retries, \
273 .flags = _flags, \
274 }
275
276 #define NKMP_CLK_WITH_UPDATE(_clkname, \
277 _id, _name, _pnames, \
278 _offset, \
279 _n_shift, _n_width, _n_value, _n_flags, \
280 _k_shift, _k_width, _k_value, _k_flags, \
281 _m_shift, _m_width, _m_value, _m_flags, \
282 _p_shift, _p_width, _p_value, _p_flags, \
283 _gate, \
284 _lock, _lock_retries, \
285 _update, \
286 _flags) \
287 static struct aw_clk_nkmp_def _clkname = { \
288 .clkdef = { \
289 .id = _id, \
290 .name = _name, \
291 .parent_names = _pnames, \
292 .parent_cnt = nitems(_pnames), \
293 }, \
294 .offset = _offset, \
295 .n.shift = _n_shift, \
296 .n.width = _n_width, \
297 .n.value = _n_value, \
298 .n.flags = _n_flags, \
299 .k.shift = _k_shift, \
300 .k.width = _k_width, \
301 .k.value = _k_value, \
302 .k.flags = _k_flags, \
303 .m.shift = _m_shift, \
304 .m.width = _m_width, \
305 .m.value = _m_value, \
306 .m.flags = _m_flags, \
307 .p.shift = _p_shift, \
308 .p.width = _p_width, \
309 .p.value = _p_value, \
310 .p.flags = _p_flags, \
311 .gate_shift = _gate, \
312 .lock_shift = _lock, \
313 .lock_retries = _lock_retries, \
314 .update_shift = _update, \
315 .flags = _flags | AW_CLK_HAS_UPDATE, \
316 }
317
318 #define FRAC_CLK(_clkname, _id, _name, _pnames, \
319 _offset, \
320 _nshift, _nwidth, _nvalue, _nflags, \
321 _mshift, _mwidth, _mvalue, _mflags, \
322 _gate_shift, _lock_shift,_lock_retries, \
323 _flags, _freq0, _freq1, _mode_sel, _freq_sel, \
324 _min_freq, _max_freq) \
325 static struct aw_clk_frac_def _clkname = { \
326 .clkdef = { \
327 .id = _id, \
328 .name = _name, \
329 .parent_names = _pnames, \
330 .parent_cnt = nitems(_pnames), \
331 .flags = CLK_NODE_GLITCH_FREE, \
332 }, \
333 .offset = _offset, \
334 .n.shift = _nshift, \
335 .n.width = _nwidth, \
336 .n.value = _nvalue, \
337 .n.flags = _nflags, \
338 .m.shift = _mshift, \
339 .m.width = _mwidth, \
340 .m.value = _mvalue, \
341 .m.flags = _mflags, \
342 .gate_shift = _gate_shift, \
343 .lock_shift = _lock_shift, \
344 .lock_retries = _lock_retries, \
345 .flags = _flags, \
346 .frac.freq0 = _freq0, \
347 .frac.freq1 = _freq1, \
348 .frac.mode_sel = _mode_sel, \
349 .frac.freq_sel = _freq_sel, \
350 .min_freq = _min_freq, \
351 .max_freq = _max_freq, \
352 }
353
354 #define M_CLK(_clkname, _id, _name, _pnames, \
355 _offset, \
356 _mshift, _mwidth, _mvalue, _mflags, \
357 _mux_shift, _mux_width, \
358 _gate_shift, \
359 _flags) \
360 static struct aw_clk_m_def _clkname = { \
361 .clkdef = { \
362 .id = _id, \
363 .name = _name, \
364 .parent_names = _pnames, \
365 .parent_cnt = nitems(_pnames), \
366 }, \
367 .offset = _offset, \
368 .mux_shift = _mux_shift, \
369 .m.shift = _mshift, \
370 .m.width = _mwidth, \
371 .m.value = _mvalue, \
372 .m.flags = _mflags, \
373 .mux_width = _mux_width, \
374 .gate_shift = _gate_shift, \
375 .flags = _flags, \
376 }
377
378 #define NM_CLK(_clkname, _id, _name, _pnames, \
379 _offset, \
380 _nshift, _nwidth, _nvalue, _nflags, \
381 _mshift, _mwidth, _mvalue, _mflags, \
382 _mux_shift, _mux_width, \
383 _gate_shift, \
384 _flags) \
385 static struct aw_clk_nm_def _clkname = { \
386 .clkdef = { \
387 .id = _id, \
388 .name = _name, \
389 .parent_names = _pnames, \
390 .parent_cnt = nitems(_pnames), \
391 }, \
392 .offset = _offset, \
393 .n.shift = _nshift, \
394 .n.width = _nwidth, \
395 .n.value = _nvalue, \
396 .n.flags = _nflags, \
397 .mux_shift = _mux_shift, \
398 .m.shift = _mshift, \
399 .m.width = _mwidth, \
400 .m.value = _mvalue, \
401 .m.flags = _mflags, \
402 .mux_width = _mux_width, \
403 .gate_shift = _gate_shift, \
404 .flags = _flags, \
405 }
406
407 #define NMM_CLK(_clkname, _id, _name, _pnames, \
408 _offset, \
409 _nshift, _nwidth, _nvalue, _nflags, \
410 _m0shift, _m0width, _m0value, _m0flags, \
411 _m1shift, _m1width, _m1value, _m1flags, \
412 _gate_shift, \
413 _lock, _lock_retries, \
414 _flags) \
415 static struct aw_clk_nmm_def _clkname = { \
416 .clkdef = { \
417 .id = _id, \
418 .name = _name, \
419 .parent_names = _pnames, \
420 .parent_cnt = nitems(_pnames), \
421 }, \
422 .offset = _offset, \
423 .n.shift = _nshift, \
424 .n.width = _nwidth, \
425 .n.value = _nvalue, \
426 .n.flags = _nflags, \
427 .m0.shift = _m0shift, \
428 .m0.width = _m0width, \
429 .m0.value = _m0value, \
430 .m0.flags = _m0flags, \
431 .m1.shift = _m1shift, \
432 .m1.width = _m1width, \
433 .m1.value = _m1value, \
434 .m1.flags = _m1flags, \
435 .gate_shift = _gate_shift, \
436 .lock_shift = _lock, \
437 .lock_retries = _lock_retries, \
438 .flags = _flags, \
439 }
440
441 #define NP_CLK(_clkname, _id, _name, _pnames, \
442 _offset, \
443 _nshift, _nwidth, _nvalue, _nflags, \
444 _pshift, _pwidth, _pvalue, _pflags, \
445 _gate_shift, \
446 _lock, _lock_retries, \
447 _flags) \
448 static struct aw_clk_np_def _clkname = { \
449 .clkdef = { \
450 .id = _id, \
451 .name = _name, \
452 .parent_names = _pnames, \
453 .parent_cnt = nitems(_pnames), \
454 }, \
455 .offset = _offset, \
456 .n.shift = _nshift, \
457 .n.width = _nwidth, \
458 .n.value = _nvalue, \
459 .n.flags = _nflags, \
460 .p.shift = _pshift, \
461 .p.width = _pwidth, \
462 .p.value = _pvalue, \
463 .p.flags = _pflags, \
464 .gate_shift = _gate_shift, \
465 .lock_shift = _lock, \
466 .lock_retries = _lock_retries, \
467 .flags = _flags, \
468 }
469
470 #define PREDIV_CLK(_clkname, _id, _name, _pnames, \
471 _offset, \
472 _mux_shift, _mux_width, \
473 _div_shift, _div_width, _div_value, _div_flags, \
474 _prediv_shift, _prediv_width, _prediv_value, _prediv_flags, \
475 _prediv_cond_shift, _prediv_cond_width, _prediv_cond_value) \
476 static struct aw_clk_prediv_mux_def _clkname = { \
477 .clkdef = { \
478 .id = _id, \
479 .name = _name, \
480 .parent_names = _pnames, \
481 .parent_cnt = nitems(_pnames), \
482 }, \
483 .offset = _offset, \
484 .mux_shift = _mux_shift, \
485 .mux_width = _mux_width, \
486 .div.shift = _div_shift, \
487 .div.width = _div_width, \
488 .div.value = _div_value, \
489 .div.flags = _div_flags, \
490 .prediv.shift = _prediv_shift, \
491 .prediv.width = _prediv_width, \
492 .prediv.value = _prediv_value, \
493 .prediv.flags = _prediv_flags, \
494 .prediv.cond_shift = _prediv_cond_shift, \
495 .prediv.cond_width = _prediv_cond_width, \
496 .prediv.cond_value = _prediv_cond_value, \
497 }
498
499 #define PREDIV_CLK_WITH_MASK(_clkname, _id, _name, _pnames, \
500 _offset, \
501 _mux_shift, _mux_width, \
502 _div_shift, _div_width, _div_value, _div_flags, \
503 _prediv_shift, _prediv_width, _prediv_value, _prediv_flags, \
504 _prediv_cond_mask, _prediv_cond_value) \
505 static struct aw_clk_prediv_mux_def _clkname = { \
506 .clkdef = { \
507 .id = _id, \
508 .name = _name, \
509 .parent_names = _pnames, \
510 .parent_cnt = nitems(_pnames), \
511 }, \
512 .offset = _offset, \
513 .mux_shift = _mux_shift, \
514 .mux_width = _mux_width, \
515 .div.shift = _div_shift, \
516 .div.width = _div_width, \
517 .div.value = _div_value, \
518 .div.flags = _div_flags, \
519 .prediv.shift = _prediv_shift, \
520 .prediv.width = _prediv_width, \
521 .prediv.value = _prediv_value, \
522 .prediv.flags = _prediv_flags, \
523 .prediv.cond_shift = 0, \
524 .prediv.cond_width = 0, \
525 .prediv.cond_mask = _prediv_cond_mask, \
526 .prediv.cond_value = _prediv_cond_value, \
527 }
528
529 #define MIPI_CLK(_clkname, _id, _name, _pnames, \
530 _offset, \
531 _kshift, _kwidth, _kflags, _kmin, \
532 _mshift, _mwidth, \
533 _nshift, _nwidth, \
534 _gate_shift, _lock_shift) \
535 static struct aw_clk_mipi_def _clkname = { \
536 .clkdef = { \
537 .id = _id, \
538 .name = _name, \
539 .parent_names = _pnames, \
540 .parent_cnt = nitems(_pnames) \
541 }, \
542 .offset = _offset, \
543 .k.shift = _kshift, \
544 .k.width = _kwidth, \
545 .k.flags = _kflags, \
546 .k.min_value = _kmin, \
547 .m.shift = _mshift, \
548 .m.width = _mwidth, \
549 .n.shift = _nshift, \
550 .n.width = _nwidth, \
551 .gate_shift = _gate_shift, \
552 .lock_shift = _lock_shift, \
553 }
554
555 #define MUX_CLK(_clkname, _id, _name, _pnames, \
556 _offset, _shift, _width) \
557 static struct clk_mux_def _clkname = { \
558 .clkdef = { \
559 .id = _id, \
560 .name = _name, \
561 .parent_names = _pnames, \
562 .parent_cnt = nitems(_pnames) \
563 }, \
564 .offset = _offset, \
565 .shift = _shift, \
566 .width = _width, \
567 }
568
569 #define DIV_CLK(_clkname, _id, _name, _pnames, \
570 _offset, \
571 _i_shift, _i_width, \
572 _div_flags, _div_table) \
573 static struct clk_div_def _clkname = { \
574 .clkdef = { \
575 .id = _id, \
576 .name = _name, \
577 .parent_names = _pnames, \
578 .parent_cnt = nitems(_pnames) \
579 }, \
580 .offset = _offset, \
581 .i_shift = _i_shift, \
582 .i_width = _i_width, \
583 .div_flags = _div_flags, \
584 .div_table = _div_table, \
585 }
586
587 #define FIXED_CLK(_clkname, _id, _name, _pnames, \
588 _freq, _mult, _div, _flags) \
589 static struct clk_fixed_def _clkname = { \
590 .clkdef = { \
591 .id = _id, \
592 .name = _name, \
593 .parent_names = _pnames, \
594 .parent_cnt = 1, \
595 }, \
596 .freq = _freq, \
597 .mult = _mult, \
598 .div = _div, \
599 .fixed_flags = _flags, \
600 }
601
602 #endif /* __AW_CLK_H__ */
603