xref: /freebsd-12.1/sys/arm/allwinner/clkng/aw_clk.h (revision 8c86cbf0)
1 /*-
2  * Copyright (c) 2017 Emmanuel Vadot <[email protected]>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
19  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
21  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28 
29 #ifndef	__AW_CLK_H__
30 #define __AW_CLK_H__
31 
32 /*
33   Allwinner clocks formula :
34 
35 PLLs:
36 
37 (24MHz*N*K)/(M*P)
38 (24MHz*N)/(M*P)
39 (24MHz*N*2)/M
40 (24MHz*N)/M
41 (24MHz*N*K)/M
42 (24MHz*N*K/2)
43 (24MHz*N)/M
44 (24MHz*N*K/2)
45 (24MHz*N)/M
46 
47 Periph clocks:
48 
49 Clock Source/Divider N/Divider M
50 Clock Source/Divider N/Divider M/2
51 Clock Source*N/(Divider M+1)/(Divider P+1)
52 
53  */
54 
55 struct aw_clk_init {
56 	const char	*name;
57 	const char	*parent_name;
58 	uint64_t	default_freq;
59 	bool		enable;
60 };
61 
62 #define	AW_CLK_HAS_GATE		0x0001
63 #define	AW_CLK_HAS_LOCK		0x0002
64 #define	AW_CLK_HAS_MUX		0x0004
65 #define	AW_CLK_REPARENT		0x0008
66 #define	AW_CLK_SCALE_CHANGE	0x0010
67 #define	AW_CLK_HAS_UPDATE	0x0040
68 #define	AW_CLK_HAS_PREDIV	0x0080
69 
70 #define	AW_CLK_FACTOR_POWER_OF_TWO	0x0001
71 #define	AW_CLK_FACTOR_ZERO_BASED	0x0002
72 #define	AW_CLK_FACTOR_HAS_COND		0x0004
73 #define	AW_CLK_FACTOR_FIXED		0x0008
74 #define	AW_CLK_FACTOR_ZERO_IS_ONE	0x0010
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	flags;		/* Flags */
88 };
89 
90 struct aw_clk_frac {
91 	uint64_t	freq0;
92 	uint64_t	freq1;
93 	uint32_t	mode_sel;
94 	uint32_t	freq_sel;
95 };
96 
97 static inline uint32_t
aw_clk_get_factor(uint32_t val,struct aw_clk_factor * factor)98 aw_clk_get_factor(uint32_t val, struct aw_clk_factor *factor)
99 {
100 	uint32_t factor_val;
101 	uint32_t cond;
102 
103 	if (factor->flags & AW_CLK_FACTOR_HAS_COND) {
104 		cond = (val & factor->cond_mask) >> factor->cond_shift;
105 		if (cond != factor->cond_value)
106 			return (1);
107 	}
108 
109 	if (factor->flags & AW_CLK_FACTOR_FIXED)
110 		return (factor->value);
111 
112 	factor_val = (val & factor->mask) >> factor->shift;
113 	if (factor_val == 0 && (factor->flags & AW_CLK_FACTOR_ZERO_IS_ONE))
114 		factor_val = 1;
115 
116 	if (factor->flags & AW_CLK_FACTOR_POWER_OF_TWO)
117 		factor_val = 1 << factor_val;
118 	else if (!(factor->flags & AW_CLK_FACTOR_ZERO_BASED))
119 		factor_val += 1;
120 
121 	return (factor_val);
122 }
123 
124 static inline uint32_t
aw_clk_factor_get_max(struct aw_clk_factor * factor)125 aw_clk_factor_get_max(struct aw_clk_factor *factor)
126 {
127 	uint32_t max;
128 
129 	if (factor->flags & AW_CLK_FACTOR_FIXED)
130 		max = factor->value;
131 	else if (factor->flags & AW_CLK_FACTOR_POWER_OF_TWO)
132 		max = 1 << ((1 << factor->width) - 1);
133 	else {
134 		max = (1 << factor->width);
135 	}
136 
137 	return (max);
138 }
139 
140 static inline uint32_t
aw_clk_factor_get_min(struct aw_clk_factor * factor)141 aw_clk_factor_get_min(struct aw_clk_factor *factor)
142 {
143 	uint32_t min;
144 
145 	if (factor->flags & AW_CLK_FACTOR_FIXED)
146 		min = factor->value;
147 	else if (factor->flags & AW_CLK_FACTOR_ZERO_BASED)
148 		min = 0;
149 	else
150 		min = 1;
151 
152 	return (min);
153 }
154 
155 static inline uint32_t
aw_clk_factor_get_value(struct aw_clk_factor * factor,uint32_t raw)156 aw_clk_factor_get_value(struct aw_clk_factor *factor, uint32_t raw)
157 {
158 	uint32_t val;
159 
160 	if (factor->flags & AW_CLK_FACTOR_FIXED)
161 		return (factor->value);
162 
163 	if (factor->flags & AW_CLK_FACTOR_ZERO_BASED)
164 		val = raw;
165 	else if (factor->flags & AW_CLK_FACTOR_POWER_OF_TWO) {
166 		for (val = 0; raw != 1; val++)
167 			raw >>= 1;
168 	} else
169 		val = raw - 1;
170 
171 	return (val);
172 }
173 
174 #define	CCU_RESET(idx, o, s)	\
175 	[idx] = {		\
176 		.offset = o,	\
177 		.shift = s,	\
178 	},
179 
180 #define	CCU_GATE(idx, clkname, pname, o, s)	\
181 	[idx] = {				\
182 		.name = clkname,		\
183 		.parent_name = pname,		\
184 		.offset = o,			\
185 		.shift = s,			\
186 	},
187 
188 #define NKMP_CLK(_clkname, _id, _name, _pnames,		\
189   _offset,						\
190   _n_shift, _n_width, _n_value, _n_flags,		\
191   _k_shift, _k_width, _k_value, _k_flags,		\
192   _m_shift, _m_width, _m_value, _m_flags,		\
193   _p_shift, _p_width, _p_value, _p_flags,		\
194   _gate,						\
195   _lock, _lock_retries,					\
196   _flags)						\
197 	static struct aw_clk_nkmp_def _clkname = {	\
198 		.clkdef = {				\
199 			.id = _id,			\
200 			.name = _name,			\
201 			.parent_names = _pnames,	\
202 			.parent_cnt = nitems(_pnames),	\
203 		},					\
204 		.offset = _offset,			\
205 		.n.shift = _n_shift,			\
206 		.n.width = _n_width,			\
207 		.n.value = _n_value,			\
208 		.n.flags = _n_flags,			\
209 		.k.shift = _k_shift,			\
210 		.k.width = _k_width,			\
211 		.k.value = _k_value,			\
212 		.k.flags = _k_flags,			\
213 		.m.shift = _m_shift,			\
214 		.m.width = _m_width,			\
215 		.m.value = _m_value,			\
216 		.m.flags = _m_flags,			\
217 		.p.shift = _p_shift,			\
218 		.p.width = _p_width,			\
219 		.p.value = _p_value,			\
220 		.p.flags = _p_flags,			\
221 		.gate_shift = _gate,			\
222 		.lock_shift = _lock,			\
223 		.lock_retries = _lock_retries,		\
224 		.flags = _flags,			\
225 	}
226 
227 #define NKMP_CLK_WITH_MUX(_clkname,			\
228   _id, _name, _pnames,					\
229   _offset,						\
230   _n_shift, _n_width, _n_value, _n_flags,		\
231   _k_shift, _k_width, _k_value, _k_flags,		\
232   _m_shift, _m_width, _m_value, _m_flags,		\
233   _p_shift, _p_width, _p_value, _p_flags,		\
234   _mux_shift, _mux_width, _gate,			\
235   _lock, _lock_retries,					\
236   _flags)						\
237 	static struct aw_clk_nkmp_def _clkname = {	\
238 		.clkdef = {				\
239 			.id = _id,			\
240 			.name = _name,			\
241 			.parent_names = _pnames,	\
242 			.parent_cnt = nitems(_pnames),	\
243 		},					\
244 		.offset = _offset,			\
245 		.n.shift = _n_shift,			\
246 		.n.width = _n_width,			\
247 		.n.value = _n_value,			\
248 		.n.flags = _n_flags,			\
249 		.k.shift = _k_shift,			\
250 		.k.width = _k_width,			\
251 		.k.value = _k_value,			\
252 		.k.flags = _k_flags,			\
253 		.m.shift = _m_shift,			\
254 		.m.width = _m_width,			\
255 		.m.value = _m_value,			\
256 		.m.flags = _m_flags,			\
257 		.p.shift = _p_shift,			\
258 		.p.width = _p_width,			\
259 		.p.value = _p_value,			\
260 		.p.flags = _p_flags,			\
261 		.mux_shift = _mux_shift,		\
262 		.mux_width = _mux_width,		\
263 		.gate_shift = _gate,			\
264 		.lock_shift = _lock,			\
265 		.lock_retries = _lock_retries,		\
266 		.flags = _flags,			\
267 	}
268 
269 #define NKMP_CLK_WITH_UPDATE(_clkname,			\
270   _id, _name, _pnames,					\
271   _offset,						\
272   _n_shift, _n_width, _n_value, _n_flags,		\
273   _k_shift, _k_width, _k_value, _k_flags,		\
274   _m_shift, _m_width, _m_value, _m_flags,		\
275   _p_shift, _p_width, _p_value, _p_flags,		\
276   _gate,						\
277   _lock, _lock_retries,					\
278   _update,						\
279   _flags)						\
280 	static struct aw_clk_nkmp_def _clkname = {	\
281 		.clkdef = {				\
282 			.id = _id,			\
283 			.name = _name,			\
284 			.parent_names = _pnames,	\
285 			.parent_cnt = nitems(_pnames),	\
286 		},					\
287 		.offset = _offset,			\
288 		.n.shift = _n_shift,			\
289 		.n.width = _n_width,			\
290 		.n.value = _n_value,			\
291 		.n.flags = _n_flags,			\
292 		.k.shift = _k_shift,			\
293 		.k.width = _k_width,			\
294 		.k.value = _k_value,			\
295 		.k.flags = _k_flags,			\
296 		.m.shift = _m_shift,			\
297 		.m.width = _m_width,			\
298 		.m.value = _m_value,			\
299 		.m.flags = _m_flags,			\
300 		.p.shift = _p_shift,			\
301 		.p.width = _p_width,			\
302 		.p.value = _p_value,			\
303 		.p.flags = _p_flags,			\
304 		.gate_shift = _gate,			\
305 		.lock_shift = _lock,			\
306 		.lock_retries = _lock_retries,		\
307 		.update_shift = _update,		\
308 		.flags = _flags | AW_CLK_HAS_UPDATE,	\
309 	}
310 
311 #define FRAC_CLK(_clkname, _id, _name, _pnames,	\
312      _offset,						\
313      _nshift, _nwidth, _nvalue, _nflags,		\
314      _mshift, _mwidth, _mvalue, _mflags,		\
315      _gate_shift, _lock_shift,_lock_retries,		\
316     _flags, _freq0, _freq1, _mode_sel, _freq_sel)	\
317 	static struct aw_clk_frac_def _clkname = {	\
318 		.clkdef = {				\
319 			.id = _id,			\
320 			.name = _name,			\
321 			.parent_names = _pnames,	\
322 			.parent_cnt = nitems(_pnames),	\
323 		},					\
324 		.offset = _offset,			\
325 		.n.shift = _nshift,			\
326 		.n.width = _nwidth,			\
327 		.n.value = _nvalue,			\
328 		.n.flags = _nflags,			\
329 		.m.shift = _mshift,			\
330 		.m.width = _mwidth,			\
331 		.m.value = _mvalue,			\
332 		.m.flags = _mflags,			\
333 		.gate_shift = _gate_shift,		\
334 		.lock_shift = _lock_shift,		\
335 		.lock_retries = _lock_retries,		\
336 		.flags = _flags,			\
337 		.frac.freq0 = _freq0,			\
338 		.frac.freq1 = _freq1,			\
339 		.frac.mode_sel = _mode_sel,		\
340 		.frac.freq_sel = _freq_sel,		\
341 	}
342 
343 #define NM_CLK(_clkname, _id, _name, _pnames,		\
344      _offset,						\
345      _nshift, _nwidth, _nvalue, _nflags,		\
346      _mshift, _mwidth, _mvalue, _mflags,		\
347     _mux_shift, _mux_width,				\
348     _gate_shift,					\
349     _flags)						\
350 	static struct aw_clk_nm_def _clkname = 	{	\
351 		.clkdef = {				\
352 			.id = _id,			\
353 			.name = _name,			\
354 			.parent_names = _pnames,	\
355 			.parent_cnt = nitems(_pnames),	\
356 		},					\
357 		.offset = _offset,			\
358 		.n.shift = _nshift,			\
359 		.n.width = _nwidth,			\
360 		.n.value = _nvalue,			\
361 		.n.flags = _nflags,			\
362 		.mux_shift = _mux_shift,		\
363 		.m.shift = _mshift,			\
364 		.m.width = _mwidth,			\
365 		.m.value = _mvalue,			\
366 		.m.flags = _mflags,			\
367 		.mux_width = _mux_width,		\
368 		.gate_shift = _gate_shift,		\
369 		.flags = _flags,			\
370 	}
371 
372 #define PREDIV_CLK(_clkname, _id, _name, _pnames,	\
373   _offset,	\
374   _mux_shift, _mux_width,	\
375   _div_shift, _div_width, _div_value, _div_flags,	\
376   _prediv_shift, _prediv_width, _prediv_value, _prediv_flags,	\
377   _prediv_cond_shift, _prediv_cond_width, _prediv_cond_value)	\
378 	static struct aw_clk_prediv_mux_def _clkname = {	\
379 		.clkdef = {					\
380 			.id = _id,				\
381 			.name = _name,				\
382 			.parent_names = _pnames,		\
383 			.parent_cnt = nitems(_pnames),		\
384 		},						\
385 		.offset = _offset,				\
386 		.mux_shift = _mux_shift,			\
387 		.mux_width = _mux_width,			\
388 		.div.shift = _div_shift,			\
389 		.div.width = _div_width,			\
390 		.div.value = _div_value,			\
391 		.div.flags = _div_flags,			\
392 		.prediv.shift = _prediv_shift,			\
393 		.prediv.width = _prediv_width,			\
394 		.prediv.value = _prediv_value,			\
395 		.prediv.flags = _prediv_flags,			\
396 		.prediv.cond_shift = _prediv_cond_shift,	\
397 		.prediv.cond_width = _prediv_cond_width,	\
398 		.prediv.cond_value = _prediv_cond_value,	\
399 	}
400 
401 #define PREDIV_CLK_WITH_MASK(_clkname, _id, _name, _pnames,	\
402   _offset,							\
403   _mux_shift, _mux_width,					\
404   _div_shift, _div_width, _div_value, _div_flags,		\
405   _prediv_shift, _prediv_width, _prediv_value, _prediv_flags,	\
406   _prediv_cond_mask, _prediv_cond_value)			\
407 	static struct aw_clk_prediv_mux_def _clkname = {	\
408 		.clkdef = {					\
409 			.id = _id,				\
410 			.name = _name,				\
411 			.parent_names = _pnames,		\
412 			.parent_cnt = nitems(_pnames),		\
413 		},						\
414 		.offset = _offset,				\
415 		.mux_shift = _mux_shift,			\
416 		.mux_width = _mux_width,			\
417 		.div.shift = _div_shift,			\
418 		.div.width = _div_width,			\
419 		.div.value = _div_value,			\
420 		.div.flags = _div_flags,			\
421 		.prediv.shift = _prediv_shift,			\
422 		.prediv.width = _prediv_width,			\
423 		.prediv.value = _prediv_value,			\
424 		.prediv.flags = _prediv_flags,			\
425 		.prediv.cond_shift = 0,				\
426 		.prediv.cond_width = 0,				\
427 		.prediv.cond_mask = _prediv_cond_mask,		\
428 		.prediv.cond_value = _prediv_cond_value,	\
429 	}
430 
431 #define MUX_CLK(_clkname, _id, _name, _pnames,		\
432   _offset,  _shift,  _width)				\
433 	static struct clk_mux_def _clkname = {	\
434 		.clkdef = {				\
435 			.id = _id,			\
436 			.name = _name,			\
437 			.parent_names = _pnames,	\
438 			.parent_cnt = nitems(_pnames)	\
439 		},					\
440 		.offset = _offset,			\
441 		.shift = _shift,			\
442 		.width = _width,			\
443 	}
444 
445 #define DIV_CLK(_clkname, _id, _name, _pnames,		\
446   _offset,						\
447   _i_shift, _i_width,					\
448   _div_flags, _div_table)				\
449 	static struct clk_div_def _clkname = {		\
450 		.clkdef = {				\
451 			.id = _id,			\
452 			.name = _name,			\
453 			.parent_names = _pnames,	\
454 			.parent_cnt = nitems(_pnames)	\
455 		},					\
456 		.offset = _offset,			\
457 		.i_shift = _i_shift,			\
458 		.i_width = _i_width,			\
459 		.div_flags = _div_flags,		\
460 		.div_table = _div_table,		\
461 	}
462 
463 #define FIXED_CLK(_clkname, _id, _name, _pnames,	\
464   _freq, _mult, _div, _flags)				\
465 	static struct clk_fixed_def _clkname = {	\
466 		.clkdef = {				\
467 			.id = _id,			\
468 			.name = _name,			\
469 			.parent_names = _pnames,	\
470 			.parent_cnt = 1,		\
471 		},					\
472 		.freq = _freq,				\
473 		.mult = _mult,				\
474 		.div = _div,				\
475 		.fixed_flags = _flags,			\
476 	}
477 
478 #endif /* __AW_CLK_H__ */
479