xref: /freebsd/sys/dev/clk/allwinner/aw_clk.h (revision 783d3ff6)
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
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
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
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
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