xref: /netbsd-src/sys/arch/arm/sunxi/sunxi_ccu.h (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /* $NetBSD: sunxi_ccu.h,v 1.18 2018/05/08 22:05:25 jmcneill 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 };
117 
118 int	sunxi_ccu_nkmp_enable(struct sunxi_ccu_softc *,
119 			      struct sunxi_ccu_clk *, int);
120 u_int	sunxi_ccu_nkmp_get_rate(struct sunxi_ccu_softc *,
121 				struct sunxi_ccu_clk *);
122 int	sunxi_ccu_nkmp_set_rate(struct sunxi_ccu_softc *,
123 				struct sunxi_ccu_clk *, u_int);
124 const char *sunxi_ccu_nkmp_get_parent(struct sunxi_ccu_softc *,
125 				      struct sunxi_ccu_clk *);
126 
127 #define	SUNXI_CCU_NKMP_TABLE(_id, _name, _parent, _reg, _n, _k, _m, \
128 		       _p, _enable, _lock, _tbl, _flags)	\
129 	[_id] = {						\
130 		.type = SUNXI_CCU_NKMP,				\
131 		.base.name = (_name),				\
132 		.u.nkmp.reg = (_reg),				\
133 		.u.nkmp.parent = (_parent),			\
134 		.u.nkmp.n = (_n),				\
135 		.u.nkmp.k = (_k),				\
136 		.u.nkmp.m = (_m),				\
137 		.u.nkmp.p = (_p),				\
138 		.u.nkmp.enable = (_enable),			\
139 		.u.nkmp.flags = (_flags),			\
140 		.u.nkmp.lock = (_lock),				\
141 		.u.nkmp.table = (_tbl),				\
142 		.enable = sunxi_ccu_nkmp_enable,		\
143 		.get_rate = sunxi_ccu_nkmp_get_rate,		\
144 		.set_rate = sunxi_ccu_nkmp_set_rate,		\
145 		.get_parent = sunxi_ccu_nkmp_get_parent,	\
146 	}
147 
148 #define	SUNXI_CCU_NKMP(_id, _name, _parent, _reg, _n, _k, _m,	\
149 		       _p, _enable, _flags)			\
150 	SUNXI_CCU_NKMP_TABLE(_id, _name, _parent, _reg, _n, _k, _m, \
151 			     _p, _enable, 0, NULL, _flags)
152 
153 
154 struct sunxi_ccu_nm {
155 	bus_size_t	reg;
156 	const char	**parents;
157 	u_int		nparents;
158 	uint32_t	n;
159 	uint32_t	m;
160 	uint32_t	sel;
161 	uint32_t	enable;
162 	uint32_t	flags;
163 #define	SUNXI_CCU_NM_POWER_OF_TWO	__BIT(0)
164 #define	SUNXI_CCU_NM_ROUND_DOWN		__BIT(1)
165 #define	SUNXI_CCU_NM_DIVIDE_BY_TWO	__BIT(2)
166 };
167 
168 int	sunxi_ccu_nm_enable(struct sunxi_ccu_softc *,
169 			    struct sunxi_ccu_clk *, int);
170 u_int	sunxi_ccu_nm_get_rate(struct sunxi_ccu_softc *,
171 			      struct sunxi_ccu_clk *);
172 int	sunxi_ccu_nm_set_rate(struct sunxi_ccu_softc *,
173 			      struct sunxi_ccu_clk *, u_int);
174 int	sunxi_ccu_nm_set_parent(struct sunxi_ccu_softc *,
175 				struct sunxi_ccu_clk *,
176 				const char *);
177 const char *sunxi_ccu_nm_get_parent(struct sunxi_ccu_softc *,
178 				    struct sunxi_ccu_clk *);
179 
180 #define	SUNXI_CCU_NM(_id, _name, _parents, _reg, _n, _m, _sel,	\
181 		     _enable, _flags)				\
182 	[_id] = {						\
183 		.type = SUNXI_CCU_NM,				\
184 		.base.name = (_name),				\
185 		.u.nm.reg = (_reg),				\
186 		.u.nm.parents = (_parents),			\
187 		.u.nm.nparents = __arraycount(_parents),	\
188 		.u.nm.n = (_n),					\
189 		.u.nm.m = (_m),					\
190 		.u.nm.sel = (_sel),				\
191 		.u.nm.enable = (_enable),			\
192 		.u.nm.flags = (_flags),				\
193 		.enable = sunxi_ccu_nm_enable,			\
194 		.get_rate = sunxi_ccu_nm_get_rate,		\
195 		.set_rate = sunxi_ccu_nm_set_rate,		\
196 		.set_parent = sunxi_ccu_nm_set_parent,		\
197 		.get_parent = sunxi_ccu_nm_get_parent,		\
198 	}
199 
200 struct sunxi_ccu_div {
201 	bus_size_t	reg;
202 	const char	**parents;
203 	u_int		nparents;
204 	uint32_t	div;
205 	uint32_t	sel;
206 	uint32_t	enable;
207 	uint32_t	flags;
208 #define	SUNXI_CCU_DIV_POWER_OF_TWO	__BIT(0)
209 #define	SUNXI_CCU_DIV_ZERO_IS_ONE	__BIT(1)
210 #define	SUNXI_CCU_DIV_TIMES_TWO		__BIT(2)
211 #define	SUNXI_CCU_DIV_SET_RATE_PARENT	__BIT(3)
212 };
213 
214 int	sunxi_ccu_div_enable(struct sunxi_ccu_softc *,
215 			     struct sunxi_ccu_clk *, int);
216 u_int	sunxi_ccu_div_get_rate(struct sunxi_ccu_softc *,
217 			       struct sunxi_ccu_clk *);
218 int	sunxi_ccu_div_set_rate(struct sunxi_ccu_softc *,
219 			       struct sunxi_ccu_clk *, u_int);
220 int	sunxi_ccu_div_set_parent(struct sunxi_ccu_softc *,
221 			         struct sunxi_ccu_clk *,
222 			         const char *);
223 const char *sunxi_ccu_div_get_parent(struct sunxi_ccu_softc *,
224 				     struct sunxi_ccu_clk *);
225 
226 #define	SUNXI_CCU_DIV(_id, _name, _parents, _reg, _div,		\
227 		      _sel, _flags)				\
228 	SUNXI_CCU_DIV_GATE(_id, _name, _parents, _reg, _div,	\
229 			   _sel, 0, _flags)
230 
231 #define	SUNXI_CCU_DIV_GATE(_id, _name, _parents, _reg, _div,	\
232 		      _sel, _enable, _flags)			\
233 	[_id] = {						\
234 		.type = SUNXI_CCU_DIV,				\
235 		.base.name = (_name),				\
236 		.u.div.reg = (_reg),				\
237 		.u.div.parents = (_parents),			\
238 		.u.div.nparents = __arraycount(_parents),	\
239 		.u.div.div = (_div),				\
240 		.u.div.sel = (_sel),				\
241 		.u.div.enable = (_enable),			\
242 		.u.div.flags = (_flags),			\
243 		.enable = sunxi_ccu_div_enable,			\
244 		.get_rate = sunxi_ccu_div_get_rate,		\
245 		.set_rate = sunxi_ccu_div_set_rate,		\
246 		.set_parent = sunxi_ccu_div_set_parent,		\
247 		.get_parent = sunxi_ccu_div_get_parent,		\
248 	}
249 
250 /* special case of the div model for display clocks */
251 int sunxi_ccu_lcdxch0_set_rate(struct sunxi_ccu_softc *,
252     struct sunxi_ccu_clk *, struct sunxi_ccu_clk *,
253     struct sunxi_ccu_clk *, u_int);
254 u_int sunxi_ccu_lcdxch0_round_rate(struct sunxi_ccu_softc *,
255     struct sunxi_ccu_clk *, struct sunxi_ccu_clk *,
256     struct sunxi_ccu_clk *, u_int);
257 
258 int sunxi_ccu_lcdxch1_set_rate(struct sunxi_ccu_softc *sc,
259     struct sunxi_ccu_clk *clk, struct sunxi_ccu_clk *pclk,
260     struct sunxi_ccu_clk *pclk_x2, u_int);
261 
262 struct sunxi_ccu_prediv {
263 	bus_size_t	reg;
264 	const char	**parents;
265 	u_int		nparents;
266 	uint32_t	prediv;
267 	uint32_t	prediv_sel;
268 	uint32_t	prediv_fixed;
269 	uint32_t	div;
270 	uint32_t	sel;
271 	uint32_t	flags;
272 #define	SUNXI_CCU_PREDIV_POWER_OF_TWO	__BIT(0)
273 #define	SUNXI_CCU_PREDIV_DIVIDE_BY_TWO	__BIT(1)
274 };
275 
276 u_int	sunxi_ccu_prediv_get_rate(struct sunxi_ccu_softc *,
277 				  struct sunxi_ccu_clk *);
278 int	sunxi_ccu_prediv_set_rate(struct sunxi_ccu_softc *,
279 				  struct sunxi_ccu_clk *, u_int);
280 int	sunxi_ccu_prediv_set_parent(struct sunxi_ccu_softc *,
281 				    struct sunxi_ccu_clk *,
282 				    const char *);
283 const char *sunxi_ccu_prediv_get_parent(struct sunxi_ccu_softc *,
284 					struct sunxi_ccu_clk *);
285 
286 #define	SUNXI_CCU_PREDIV(_id, _name, _parents, _reg, _prediv,	\
287 		     _prediv_sel, _div, _sel, _flags)		\
288 	SUNXI_CCU_PREDIV_FIXED(_id, _name, _parents, _reg, _prediv, \
289 		     _prediv_sel, 0, _div, _sel, _flags)
290 
291 #define	SUNXI_CCU_PREDIV_FIXED(_id, _name, _parents, _reg, _prediv, \
292 		     _prediv_sel, _prediv_fixed, _div, _sel, _flags) \
293 	[_id] = {						\
294 		.type = SUNXI_CCU_PREDIV,			\
295 		.base.name = (_name),				\
296 		.u.prediv.reg = (_reg),				\
297 		.u.prediv.parents = (_parents),			\
298 		.u.prediv.nparents = __arraycount(_parents),	\
299 		.u.prediv.prediv = (_prediv),			\
300 		.u.prediv.prediv_sel = (_prediv_sel),		\
301 		.u.prediv.prediv_fixed = (_prediv_fixed),	\
302 		.u.prediv.div = (_div),				\
303 		.u.prediv.sel = (_sel),				\
304 		.u.prediv.flags = (_flags),			\
305 		.get_rate = sunxi_ccu_prediv_get_rate,		\
306 		.set_rate = sunxi_ccu_prediv_set_rate,		\
307 		.set_parent = sunxi_ccu_prediv_set_parent,	\
308 		.get_parent = sunxi_ccu_prediv_get_parent,	\
309 	}
310 
311 struct sunxi_ccu_phase {
312 	bus_size_t	reg;
313 	const char	*parent;
314 	uint32_t	mask;
315 };
316 
317 u_int	sunxi_ccu_phase_get_rate(struct sunxi_ccu_softc *,
318 				 struct sunxi_ccu_clk *);
319 int	sunxi_ccu_phase_set_rate(struct sunxi_ccu_softc *,
320 				 struct sunxi_ccu_clk *, u_int);
321 const char *sunxi_ccu_phase_get_parent(struct sunxi_ccu_softc *,
322 				       struct sunxi_ccu_clk *);
323 
324 #define	SUNXI_CCU_PHASE(_id, _name, _parent, _reg, _mask)	\
325 	[_id] = {						\
326 		.type = SUNXI_CCU_PHASE,			\
327 		.base.name = (_name),				\
328 		.u.phase.reg = (_reg),				\
329 		.u.phase.parent = (_parent),			\
330 		.u.phase.mask = (_mask),			\
331 		.get_rate = sunxi_ccu_phase_get_rate,		\
332 		.set_rate = sunxi_ccu_phase_set_rate,		\
333 		.get_parent = sunxi_ccu_phase_get_parent,	\
334 	}
335 
336 struct sunxi_ccu_fixed_factor {
337 	const char	*parent;
338 	u_int		div;
339 	u_int		mult;
340 };
341 
342 u_int	sunxi_ccu_fixed_factor_get_rate(struct sunxi_ccu_softc *,
343 					struct sunxi_ccu_clk *);
344 int	sunxi_ccu_fixed_factor_set_rate(struct sunxi_ccu_softc *,
345 					struct sunxi_ccu_clk *, u_int);
346 const char *sunxi_ccu_fixed_factor_get_parent(struct sunxi_ccu_softc *,
347 					      struct sunxi_ccu_clk *);
348 
349 #define	SUNXI_CCU_FIXED_FACTOR(_id, _name, _parent, _div, _mult)	\
350 	[_id] = {							\
351 		.type = SUNXI_CCU_FIXED_FACTOR,				\
352 		.base.name = (_name),					\
353 		.u.fixed_factor.parent = (_parent),			\
354 		.u.fixed_factor.div = (_div),				\
355 		.u.fixed_factor.mult = (_mult),				\
356 		.get_rate = sunxi_ccu_fixed_factor_get_rate,		\
357 		.get_parent = sunxi_ccu_fixed_factor_get_parent,	\
358 		.set_rate = sunxi_ccu_fixed_factor_set_rate,		\
359 	}
360 
361 struct sunxi_ccu_fractional {
362 	bus_size_t	reg;
363 	const char	*parent;
364 	uint32_t	m;
365 	uint32_t	m_min;
366 	uint32_t	m_max;
367 	uint32_t	div_en;
368 	uint32_t	frac_sel;
369 	uint32_t	frac[2];
370 	uint32_t	prediv;
371 	uint32_t	enable;
372 };
373 
374 int	sunxi_ccu_fractional_enable(struct sunxi_ccu_softc *,
375 			    struct sunxi_ccu_clk *, int);
376 u_int	sunxi_ccu_fractional_get_rate(struct sunxi_ccu_softc *,
377 			      struct sunxi_ccu_clk *);
378 int	sunxi_ccu_fractional_set_rate(struct sunxi_ccu_softc *,
379 			      struct sunxi_ccu_clk *, u_int);
380 u_int	sunxi_ccu_fractional_round_rate(struct sunxi_ccu_softc *,
381 			      struct sunxi_ccu_clk *, u_int);
382 const char *sunxi_ccu_fractional_get_parent(struct sunxi_ccu_softc *,
383 				    struct sunxi_ccu_clk *);
384 
385 #define	SUNXI_CCU_FRACTIONAL(_id, _name, _parent, _reg, _m, _m_min, _m_max, \
386 		     _div_en, _frac_sel, _frac0, _frac1, _prediv, _enable) \
387 	[_id] = {							\
388 		.type = SUNXI_CCU_FRACTIONAL,				\
389 		.base.name = (_name),					\
390 		.u.fractional.reg = (_reg),				\
391 		.u.fractional.parent = (_parent),			\
392 		.u.fractional.m = (_m),					\
393 		.u.fractional.m_min = (_m_min),				\
394 		.u.fractional.m_max = (_m_max),				\
395 		.u.fractional.prediv = (_prediv),			\
396 		.u.fractional.div_en = (_div_en),			\
397 		.u.fractional.frac_sel = (_frac_sel),			\
398 		.u.fractional.frac[0] = (_frac0),			\
399 		.u.fractional.frac[1] = (_frac1),			\
400 		.u.fractional.enable = (_enable),			\
401 		.enable = sunxi_ccu_fractional_enable,			\
402 		.get_rate = sunxi_ccu_fractional_get_rate,		\
403 		.set_rate = sunxi_ccu_fractional_set_rate,		\
404 		.round_rate = sunxi_ccu_fractional_round_rate,		\
405 		.get_parent = sunxi_ccu_fractional_get_parent,		\
406 	}
407 
408 struct sunxi_ccu_clk {
409 	struct clk	base;
410 	enum sunxi_ccu_clktype type;
411 	union {
412 		struct sunxi_ccu_gate gate;
413 		struct sunxi_ccu_nm nm;
414 		struct sunxi_ccu_nkmp nkmp;
415 		struct sunxi_ccu_prediv prediv;
416 		struct sunxi_ccu_div div;
417 		struct sunxi_ccu_phase phase;
418 		struct sunxi_ccu_fixed_factor fixed_factor;
419 		struct sunxi_ccu_fractional fractional;
420 	} u;
421 
422 	int		(*enable)(struct sunxi_ccu_softc *,
423 				  struct sunxi_ccu_clk *, int);
424 	u_int		(*get_rate)(struct sunxi_ccu_softc *,
425 				    struct sunxi_ccu_clk *);
426 	int		(*set_rate)(struct sunxi_ccu_softc *,
427 				    struct sunxi_ccu_clk *, u_int);
428 	u_int		(*round_rate)(struct sunxi_ccu_softc *,
429 				    struct sunxi_ccu_clk *, u_int);
430 	const char *	(*get_parent)(struct sunxi_ccu_softc *,
431 				      struct sunxi_ccu_clk *);
432 	int		(*set_parent)(struct sunxi_ccu_softc *,
433 				      struct sunxi_ccu_clk *,
434 				      const char *);
435 };
436 
437 struct sunxi_ccu_softc {
438 	device_t		sc_dev;
439 	int			sc_phandle;
440 	bus_space_tag_t		sc_bst;
441 	bus_space_handle_t	sc_bsh;
442 
443 	struct clk_domain	sc_clkdom;
444 
445 	struct sunxi_ccu_reset *sc_resets;
446 	u_int			sc_nresets;
447 
448 	struct sunxi_ccu_clk	*sc_clks;
449 	u_int			sc_nclks;
450 };
451 
452 int	sunxi_ccu_attach(struct sunxi_ccu_softc *);
453 struct sunxi_ccu_clk *sunxi_ccu_clock_find(struct sunxi_ccu_softc *,
454 					   const char *);
455 void	sunxi_ccu_print(struct sunxi_ccu_softc *);
456 
457 #define CCU_READ(sc, reg)	\
458 	bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
459 #define CCU_WRITE(sc, reg, val)	\
460 	bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
461 
462 #endif /* _ARM_SUNXI_CCU_H */
463