xref: /netbsd-src/sys/arch/arm/sunxi/sunxi_ccu.h (revision cef8759bd76c1b621f8eab8faa6f208faabc2e15)
1 /* $NetBSD: sunxi_ccu.h,v 1.22 2019/11/23 03:59:39 jakllsch Exp $ */
2 
3 /*-
4  * Copyright (c) 2017 Jared McNeill <jmcneill@invisible.ca>
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 
29 #ifndef _ARM_SUNXI_CCU_H
30 #define _ARM_SUNXI_CCU_H
31 
32 #include <dev/clk/clk_backend.h>
33 
34 struct sunxi_ccu_softc;
35 struct sunxi_ccu_clk;
36 struct sunxi_ccu_reset;
37 
38 /*
39  * Resets
40  */
41 
42 struct sunxi_ccu_reset {
43 	bus_size_t	reg;
44 	uint32_t	mask;
45 };
46 
47 #define	SUNXI_CCU_RESET(_id, _reg, _bit)	\
48 	[_id] = {				\
49 		.reg = (_reg),			\
50 		.mask = __BIT(_bit),		\
51 	}
52 
53 /*
54  * Clocks
55  */
56 
57 enum sunxi_ccu_clktype {
58 	SUNXI_CCU_UNKNOWN,
59 	SUNXI_CCU_GATE,
60 	SUNXI_CCU_NM,
61 	SUNXI_CCU_NKMP,
62 	SUNXI_CCU_PREDIV,
63 	SUNXI_CCU_DIV,
64 	SUNXI_CCU_PHASE,
65 	SUNXI_CCU_FIXED_FACTOR,
66 	SUNXI_CCU_FRACTIONAL,
67 };
68 
69 struct sunxi_ccu_gate {
70 	bus_size_t	reg;
71 	uint32_t	mask;
72 	const char	*parent;
73 };
74 
75 int	sunxi_ccu_gate_enable(struct sunxi_ccu_softc *,
76 			      struct sunxi_ccu_clk *, int);
77 const char *sunxi_ccu_gate_get_parent(struct sunxi_ccu_softc *,
78 				      struct sunxi_ccu_clk *);
79 
80 #define	SUNXI_CCU_GATE(_id, _name, _pname, _reg, _bit)		\
81 	[_id] = {						\
82 		.type = SUNXI_CCU_GATE,				\
83 		.base.name = (_name),				\
84 		.base.flags = CLK_SET_RATE_PARENT,		\
85 		.u.gate.parent = (_pname),			\
86 		.u.gate.reg = (_reg),				\
87 		.u.gate.mask = __BIT(_bit),			\
88 		.enable = sunxi_ccu_gate_enable,		\
89 		.get_parent = sunxi_ccu_gate_get_parent,	\
90 	}
91 
92 struct sunxi_ccu_nkmp_tbl {
93 	u_int		rate;
94 	uint32_t	n;
95 	uint32_t	k;
96 	uint32_t	m;
97 	uint32_t	p;
98 };
99 
100 struct sunxi_ccu_nkmp {
101 	bus_size_t	reg;
102 	const char	*parent;
103 	uint32_t	n;
104 	uint32_t	k;
105 	uint32_t	m;
106 	uint32_t	p;
107 	uint32_t	lock;
108 	uint32_t	enable;
109 	uint32_t	flags;
110 	const struct sunxi_ccu_nkmp_tbl *table;
111 #define	SUNXI_CCU_NKMP_DIVIDE_BY_TWO		__BIT(0)
112 #define	SUNXI_CCU_NKMP_FACTOR_N_EXACT		__BIT(1)
113 #define	SUNXI_CCU_NKMP_SCALE_CLOCK		__BIT(2)
114 #define	SUNXI_CCU_NKMP_FACTOR_P_POW2		__BIT(3)
115 #define	SUNXI_CCU_NKMP_FACTOR_N_ZERO_IS_ONE	__BIT(4)
116 #define	SUNXI_CCU_NKMP_FACTOR_P_X4		__BIT(5)
117 };
118 
119 int	sunxi_ccu_nkmp_enable(struct sunxi_ccu_softc *,
120 			      struct sunxi_ccu_clk *, int);
121 u_int	sunxi_ccu_nkmp_get_rate(struct sunxi_ccu_softc *,
122 				struct sunxi_ccu_clk *);
123 int	sunxi_ccu_nkmp_set_rate(struct sunxi_ccu_softc *,
124 				struct sunxi_ccu_clk *, u_int);
125 const char *sunxi_ccu_nkmp_get_parent(struct sunxi_ccu_softc *,
126 				      struct sunxi_ccu_clk *);
127 
128 #define	SUNXI_CCU_NKMP_TABLE(_id, _name, _parent, _reg, _n, _k, _m, \
129 		       _p, _enable, _lock, _tbl, _flags)	\
130 	[_id] = {						\
131 		.type = SUNXI_CCU_NKMP,				\
132 		.base.name = (_name),				\
133 		.u.nkmp.reg = (_reg),				\
134 		.u.nkmp.parent = (_parent),			\
135 		.u.nkmp.n = (_n),				\
136 		.u.nkmp.k = (_k),				\
137 		.u.nkmp.m = (_m),				\
138 		.u.nkmp.p = (_p),				\
139 		.u.nkmp.enable = (_enable),			\
140 		.u.nkmp.flags = (_flags),			\
141 		.u.nkmp.lock = (_lock),				\
142 		.u.nkmp.table = (_tbl),				\
143 		.enable = sunxi_ccu_nkmp_enable,		\
144 		.get_rate = sunxi_ccu_nkmp_get_rate,		\
145 		.set_rate = sunxi_ccu_nkmp_set_rate,		\
146 		.get_parent = sunxi_ccu_nkmp_get_parent,	\
147 	}
148 
149 #define	SUNXI_CCU_NKMP(_id, _name, _parent, _reg, _n, _k, _m,	\
150 		       _p, _enable, _flags)			\
151 	SUNXI_CCU_NKMP_TABLE(_id, _name, _parent, _reg, _n, _k, _m, \
152 			     _p, _enable, 0, NULL, _flags)
153 
154 
155 struct sunxi_ccu_nm {
156 	bus_size_t	reg;
157 	const char	**parents;
158 	u_int		nparents;
159 	uint32_t	n;
160 	uint32_t	m;
161 	uint32_t	sel;
162 	uint32_t	enable;
163 	uint32_t	flags;
164 #define	SUNXI_CCU_NM_POWER_OF_TWO	__BIT(0)
165 #define	SUNXI_CCU_NM_ROUND_DOWN		__BIT(1)
166 #define	SUNXI_CCU_NM_DIVIDE_BY_TWO	__BIT(2)
167 };
168 
169 int	sunxi_ccu_nm_enable(struct sunxi_ccu_softc *,
170 			    struct sunxi_ccu_clk *, int);
171 u_int	sunxi_ccu_nm_get_rate(struct sunxi_ccu_softc *,
172 			      struct sunxi_ccu_clk *);
173 int	sunxi_ccu_nm_set_rate(struct sunxi_ccu_softc *,
174 			      struct sunxi_ccu_clk *, u_int);
175 int	sunxi_ccu_nm_set_parent(struct sunxi_ccu_softc *,
176 				struct sunxi_ccu_clk *,
177 				const char *);
178 const char *sunxi_ccu_nm_get_parent(struct sunxi_ccu_softc *,
179 				    struct sunxi_ccu_clk *);
180 
181 #define	SUNXI_CCU_NM(_id, _name, _parents, _reg, _n, _m, _sel,	\
182 		     _enable, _flags)				\
183 	[_id] = {						\
184 		.type = SUNXI_CCU_NM,				\
185 		.base.name = (_name),				\
186 		.u.nm.reg = (_reg),				\
187 		.u.nm.parents = (_parents),			\
188 		.u.nm.nparents = __arraycount(_parents),	\
189 		.u.nm.n = (_n),					\
190 		.u.nm.m = (_m),					\
191 		.u.nm.sel = (_sel),				\
192 		.u.nm.enable = (_enable),			\
193 		.u.nm.flags = (_flags),				\
194 		.enable = sunxi_ccu_nm_enable,			\
195 		.get_rate = sunxi_ccu_nm_get_rate,		\
196 		.set_rate = sunxi_ccu_nm_set_rate,		\
197 		.set_parent = sunxi_ccu_nm_set_parent,		\
198 		.get_parent = sunxi_ccu_nm_get_parent,		\
199 	}
200 
201 struct sunxi_ccu_div {
202 	bus_size_t	reg;
203 	const char	**parents;
204 	u_int		nparents;
205 	uint32_t	div;
206 	uint32_t	sel;
207 	uint32_t	enable;
208 	uint32_t	flags;
209 #define	SUNXI_CCU_DIV_POWER_OF_TWO	__BIT(0)
210 #define	SUNXI_CCU_DIV_ZERO_IS_ONE	__BIT(1)
211 #define	SUNXI_CCU_DIV_TIMES_TWO		__BIT(2)
212 #define	SUNXI_CCU_DIV_SET_RATE_PARENT	__BIT(3)
213 };
214 
215 int	sunxi_ccu_div_enable(struct sunxi_ccu_softc *,
216 			     struct sunxi_ccu_clk *, int);
217 u_int	sunxi_ccu_div_get_rate(struct sunxi_ccu_softc *,
218 			       struct sunxi_ccu_clk *);
219 int	sunxi_ccu_div_set_rate(struct sunxi_ccu_softc *,
220 			       struct sunxi_ccu_clk *, u_int);
221 int	sunxi_ccu_div_set_parent(struct sunxi_ccu_softc *,
222 			         struct sunxi_ccu_clk *,
223 			         const char *);
224 const char *sunxi_ccu_div_get_parent(struct sunxi_ccu_softc *,
225 				     struct sunxi_ccu_clk *);
226 
227 #define	SUNXI_CCU_DIV(_id, _name, _parents, _reg, _div,		\
228 		      _sel, _flags)				\
229 	SUNXI_CCU_DIV_GATE(_id, _name, _parents, _reg, _div,	\
230 			   _sel, 0, _flags)
231 
232 #define	SUNXI_CCU_DIV_GATE(_id, _name, _parents, _reg, _div,	\
233 		      _sel, _enable, _flags)			\
234 	[_id] = {						\
235 		.type = SUNXI_CCU_DIV,				\
236 		.base.name = (_name),				\
237 		.u.div.reg = (_reg),				\
238 		.u.div.parents = (_parents),			\
239 		.u.div.nparents = __arraycount(_parents),	\
240 		.u.div.div = (_div),				\
241 		.u.div.sel = (_sel),				\
242 		.u.div.enable = (_enable),			\
243 		.u.div.flags = (_flags),			\
244 		.enable = sunxi_ccu_div_enable,			\
245 		.get_rate = sunxi_ccu_div_get_rate,		\
246 		.set_rate = sunxi_ccu_div_set_rate,		\
247 		.set_parent = sunxi_ccu_div_set_parent,		\
248 		.get_parent = sunxi_ccu_div_get_parent,		\
249 	}
250 
251 /* special case of the div model for display clocks */
252 int sunxi_ccu_lcdxch0_set_rate(struct sunxi_ccu_softc *,
253     struct sunxi_ccu_clk *, struct sunxi_ccu_clk *,
254     struct sunxi_ccu_clk *, u_int);
255 u_int sunxi_ccu_lcdxch0_round_rate(struct sunxi_ccu_softc *,
256     struct sunxi_ccu_clk *, struct sunxi_ccu_clk *,
257     struct sunxi_ccu_clk *, u_int);
258 
259 int sunxi_ccu_lcdxch1_set_rate(struct sunxi_ccu_softc *sc,
260     struct sunxi_ccu_clk *clk, struct sunxi_ccu_clk *pclk,
261     struct sunxi_ccu_clk *pclk_x2, u_int);
262 
263 struct sunxi_ccu_prediv {
264 	bus_size_t	reg;
265 	const char	**parents;
266 	u_int		nparents;
267 	uint32_t	prediv;
268 	uint32_t	prediv_sel;
269 	uint32_t	prediv_fixed;
270 	uint32_t	div;
271 	uint32_t	sel;
272 	uint32_t	flags;
273 #define	SUNXI_CCU_PREDIV_POWER_OF_TWO	__BIT(0)
274 #define	SUNXI_CCU_PREDIV_DIVIDE_BY_TWO	__BIT(1)
275 };
276 
277 u_int	sunxi_ccu_prediv_get_rate(struct sunxi_ccu_softc *,
278 				  struct sunxi_ccu_clk *);
279 int	sunxi_ccu_prediv_set_rate(struct sunxi_ccu_softc *,
280 				  struct sunxi_ccu_clk *, u_int);
281 int	sunxi_ccu_prediv_set_parent(struct sunxi_ccu_softc *,
282 				    struct sunxi_ccu_clk *,
283 				    const char *);
284 const char *sunxi_ccu_prediv_get_parent(struct sunxi_ccu_softc *,
285 					struct sunxi_ccu_clk *);
286 
287 #define	SUNXI_CCU_PREDIV(_id, _name, _parents, _reg, _prediv,	\
288 		     _prediv_sel, _div, _sel, _flags)		\
289 	SUNXI_CCU_PREDIV_FIXED(_id, _name, _parents, _reg, _prediv, \
290 		     _prediv_sel, 0, _div, _sel, _flags)
291 
292 #define	SUNXI_CCU_PREDIV_FIXED(_id, _name, _parents, _reg, _prediv, \
293 		     _prediv_sel, _prediv_fixed, _div, _sel, _flags) \
294 	[_id] = {						\
295 		.type = SUNXI_CCU_PREDIV,			\
296 		.base.name = (_name),				\
297 		.u.prediv.reg = (_reg),				\
298 		.u.prediv.parents = (_parents),			\
299 		.u.prediv.nparents = __arraycount(_parents),	\
300 		.u.prediv.prediv = (_prediv),			\
301 		.u.prediv.prediv_sel = (_prediv_sel),		\
302 		.u.prediv.prediv_fixed = (_prediv_fixed),	\
303 		.u.prediv.div = (_div),				\
304 		.u.prediv.sel = (_sel),				\
305 		.u.prediv.flags = (_flags),			\
306 		.get_rate = sunxi_ccu_prediv_get_rate,		\
307 		.set_rate = sunxi_ccu_prediv_set_rate,		\
308 		.set_parent = sunxi_ccu_prediv_set_parent,	\
309 		.get_parent = sunxi_ccu_prediv_get_parent,	\
310 	}
311 
312 struct sunxi_ccu_phase {
313 	bus_size_t	reg;
314 	const char	*parent;
315 	uint32_t	mask;
316 };
317 
318 u_int	sunxi_ccu_phase_get_rate(struct sunxi_ccu_softc *,
319 				 struct sunxi_ccu_clk *);
320 int	sunxi_ccu_phase_set_rate(struct sunxi_ccu_softc *,
321 				 struct sunxi_ccu_clk *, u_int);
322 const char *sunxi_ccu_phase_get_parent(struct sunxi_ccu_softc *,
323 				       struct sunxi_ccu_clk *);
324 
325 #define	SUNXI_CCU_PHASE(_id, _name, _parent, _reg, _mask)	\
326 	[_id] = {						\
327 		.type = SUNXI_CCU_PHASE,			\
328 		.base.name = (_name),				\
329 		.u.phase.reg = (_reg),				\
330 		.u.phase.parent = (_parent),			\
331 		.u.phase.mask = (_mask),			\
332 		.get_rate = sunxi_ccu_phase_get_rate,		\
333 		.set_rate = sunxi_ccu_phase_set_rate,		\
334 		.get_parent = sunxi_ccu_phase_get_parent,	\
335 	}
336 
337 struct sunxi_ccu_fixed_factor {
338 	const char	*parent;
339 	u_int		div;
340 	u_int		mult;
341 };
342 
343 u_int	sunxi_ccu_fixed_factor_get_rate(struct sunxi_ccu_softc *,
344 					struct sunxi_ccu_clk *);
345 int	sunxi_ccu_fixed_factor_set_rate(struct sunxi_ccu_softc *,
346 					struct sunxi_ccu_clk *, u_int);
347 const char *sunxi_ccu_fixed_factor_get_parent(struct sunxi_ccu_softc *,
348 					      struct sunxi_ccu_clk *);
349 
350 #define	SUNXI_CCU_FIXED_FACTOR(_id, _name, _parent, _div, _mult)	\
351 	[_id] = {							\
352 		.type = SUNXI_CCU_FIXED_FACTOR,				\
353 		.base.name = (_name),					\
354 		.u.fixed_factor.parent = (_parent),			\
355 		.u.fixed_factor.div = (_div),				\
356 		.u.fixed_factor.mult = (_mult),				\
357 		.get_rate = sunxi_ccu_fixed_factor_get_rate,		\
358 		.get_parent = sunxi_ccu_fixed_factor_get_parent,	\
359 		.set_rate = sunxi_ccu_fixed_factor_set_rate,		\
360 	}
361 
362 struct sunxi_ccu_fractional {
363 	bus_size_t	reg;
364 	const char	*parent;
365 	uint32_t	m;
366 	uint32_t	m_min;
367 	uint32_t	m_max;
368 	uint32_t	div_en;
369 	uint32_t	frac_sel;
370 	uint32_t	frac[2];
371 	uint32_t	prediv;
372 	uint32_t	prediv_val;
373 	uint32_t	enable;
374 	uint32_t	flags;
375 #define	SUNXI_CCU_FRACTIONAL_PLUSONE	__BIT(0)
376 #define	SUNXI_CCU_FRACTIONAL_SET_ENABLE	__BIT(1)
377 };
378 
379 int	sunxi_ccu_fractional_enable(struct sunxi_ccu_softc *,
380 			    struct sunxi_ccu_clk *, int);
381 u_int	sunxi_ccu_fractional_get_rate(struct sunxi_ccu_softc *,
382 			      struct sunxi_ccu_clk *);
383 int	sunxi_ccu_fractional_set_rate(struct sunxi_ccu_softc *,
384 			      struct sunxi_ccu_clk *, u_int);
385 u_int	sunxi_ccu_fractional_round_rate(struct sunxi_ccu_softc *,
386 			      struct sunxi_ccu_clk *, u_int);
387 const char *sunxi_ccu_fractional_get_parent(struct sunxi_ccu_softc *,
388 				    struct sunxi_ccu_clk *);
389 
390 #define	SUNXI_CCU_FRACTIONAL(_id, _name, _parent, _reg, _m, _m_min, _m_max, \
391 		     _div_en, _frac_sel, _frac0, _frac1, _prediv, _prediv_val, \
392 		     _enable, _flags)					\
393 	[_id] = {							\
394 		.type = SUNXI_CCU_FRACTIONAL,				\
395 		.base.name = (_name),					\
396 		.u.fractional.reg = (_reg),				\
397 		.u.fractional.parent = (_parent),			\
398 		.u.fractional.m = (_m),					\
399 		.u.fractional.m_min = (_m_min),				\
400 		.u.fractional.m_max = (_m_max),				\
401 		.u.fractional.prediv = (_prediv),			\
402 		.u.fractional.prediv_val = (_prediv_val),		\
403 		.u.fractional.div_en = (_div_en),			\
404 		.u.fractional.frac_sel = (_frac_sel),			\
405 		.u.fractional.frac[0] = (_frac0),			\
406 		.u.fractional.frac[1] = (_frac1),			\
407 		.u.fractional.enable = (_enable),			\
408 		.u.fractional.flags = (_flags),				\
409 		.enable = sunxi_ccu_fractional_enable,			\
410 		.get_rate = sunxi_ccu_fractional_get_rate,		\
411 		.set_rate = sunxi_ccu_fractional_set_rate,		\
412 		.round_rate = sunxi_ccu_fractional_round_rate,		\
413 		.get_parent = sunxi_ccu_fractional_get_parent,		\
414 	}
415 
416 struct sunxi_ccu_clk {
417 	struct clk	base;
418 	enum sunxi_ccu_clktype type;
419 	union {
420 		struct sunxi_ccu_gate gate;
421 		struct sunxi_ccu_nm nm;
422 		struct sunxi_ccu_nkmp nkmp;
423 		struct sunxi_ccu_prediv prediv;
424 		struct sunxi_ccu_div div;
425 		struct sunxi_ccu_phase phase;
426 		struct sunxi_ccu_fixed_factor fixed_factor;
427 		struct sunxi_ccu_fractional fractional;
428 	} u;
429 
430 	int		(*enable)(struct sunxi_ccu_softc *,
431 				  struct sunxi_ccu_clk *, int);
432 	u_int		(*get_rate)(struct sunxi_ccu_softc *,
433 				    struct sunxi_ccu_clk *);
434 	int		(*set_rate)(struct sunxi_ccu_softc *,
435 				    struct sunxi_ccu_clk *, u_int);
436 	u_int		(*round_rate)(struct sunxi_ccu_softc *,
437 				    struct sunxi_ccu_clk *, u_int);
438 	const char *	(*get_parent)(struct sunxi_ccu_softc *,
439 				      struct sunxi_ccu_clk *);
440 	int		(*set_parent)(struct sunxi_ccu_softc *,
441 				      struct sunxi_ccu_clk *,
442 				      const char *);
443 };
444 
445 struct sunxi_ccu_softc {
446 	device_t		sc_dev;
447 	int			sc_phandle;
448 	bus_space_tag_t		sc_bst;
449 	bus_space_handle_t	sc_bsh;
450 
451 	struct clk_domain	sc_clkdom;
452 
453 	struct sunxi_ccu_reset *sc_resets;
454 	u_int			sc_nresets;
455 
456 	struct sunxi_ccu_clk	*sc_clks;
457 	u_int			sc_nclks;
458 };
459 
460 int	sunxi_ccu_attach(struct sunxi_ccu_softc *);
461 struct sunxi_ccu_clk *sunxi_ccu_clock_find(struct sunxi_ccu_softc *,
462 					   const char *);
463 void	sunxi_ccu_print(struct sunxi_ccu_softc *);
464 
465 #define CCU_READ(sc, reg)	\
466 	bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
467 #define CCU_WRITE(sc, reg, val)	\
468 	bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
469 
470 #endif /* _ARM_SUNXI_CCU_H */
471