xref: /netbsd-src/sys/arch/arm/sunxi/sunxi_ccu.h (revision c38e7cc395b1472a774ff828e46123de44c628e9)
1 /* $NetBSD: sunxi_ccu.h,v 1.17 2018/04/01 21:19:17 bouyer 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 const char *sunxi_ccu_fixed_factor_get_parent(struct sunxi_ccu_softc *,
345 					      struct sunxi_ccu_clk *);
346 
347 #define	SUNXI_CCU_FIXED_FACTOR(_id, _name, _parent, _div, _mult)	\
348 	[_id] = {							\
349 		.type = SUNXI_CCU_FIXED_FACTOR,				\
350 		.base.name = (_name),					\
351 		.u.fixed_factor.parent = (_parent),			\
352 		.u.fixed_factor.div = (_div),				\
353 		.u.fixed_factor.mult = (_mult),				\
354 		.get_rate = sunxi_ccu_fixed_factor_get_rate,		\
355 		.get_parent = sunxi_ccu_fixed_factor_get_parent,	\
356 	}
357 
358 struct sunxi_ccu_fractional {
359 	bus_size_t	reg;
360 	const char	*parent;
361 	uint32_t	m;
362 	uint32_t	m_min;
363 	uint32_t	m_max;
364 	uint32_t	div_en;
365 	uint32_t	frac_sel;
366 	uint32_t	frac[2];
367 	uint32_t	prediv;
368 	uint32_t	enable;
369 };
370 
371 int	sunxi_ccu_fractional_enable(struct sunxi_ccu_softc *,
372 			    struct sunxi_ccu_clk *, int);
373 u_int	sunxi_ccu_fractional_get_rate(struct sunxi_ccu_softc *,
374 			      struct sunxi_ccu_clk *);
375 int	sunxi_ccu_fractional_set_rate(struct sunxi_ccu_softc *,
376 			      struct sunxi_ccu_clk *, u_int);
377 u_int	sunxi_ccu_fractional_round_rate(struct sunxi_ccu_softc *,
378 			      struct sunxi_ccu_clk *, u_int);
379 const char *sunxi_ccu_fractional_get_parent(struct sunxi_ccu_softc *,
380 				    struct sunxi_ccu_clk *);
381 
382 #define	SUNXI_CCU_FRACTIONAL(_id, _name, _parent, _reg, _m, _m_min, _m_max, \
383 		     _div_en, _frac_sel, _frac0, _frac1, _prediv, _enable) \
384 	[_id] = {							\
385 		.type = SUNXI_CCU_FRACTIONAL,				\
386 		.base.name = (_name),					\
387 		.u.fractional.reg = (_reg),				\
388 		.u.fractional.parent = (_parent),			\
389 		.u.fractional.m = (_m),					\
390 		.u.fractional.m_min = (_m_min),				\
391 		.u.fractional.m_max = (_m_max),				\
392 		.u.fractional.prediv = (_prediv),			\
393 		.u.fractional.div_en = (_div_en),			\
394 		.u.fractional.frac_sel = (_frac_sel),			\
395 		.u.fractional.frac[0] = (_frac0),			\
396 		.u.fractional.frac[1] = (_frac1),			\
397 		.u.fractional.enable = (_enable),			\
398 		.enable = sunxi_ccu_fractional_enable,			\
399 		.get_rate = sunxi_ccu_fractional_get_rate,		\
400 		.set_rate = sunxi_ccu_fractional_set_rate,		\
401 		.round_rate = sunxi_ccu_fractional_round_rate,		\
402 		.get_parent = sunxi_ccu_fractional_get_parent,		\
403 	}
404 
405 struct sunxi_ccu_clk {
406 	struct clk	base;
407 	enum sunxi_ccu_clktype type;
408 	union {
409 		struct sunxi_ccu_gate gate;
410 		struct sunxi_ccu_nm nm;
411 		struct sunxi_ccu_nkmp nkmp;
412 		struct sunxi_ccu_prediv prediv;
413 		struct sunxi_ccu_div div;
414 		struct sunxi_ccu_phase phase;
415 		struct sunxi_ccu_fixed_factor fixed_factor;
416 		struct sunxi_ccu_fractional fractional;
417 	} u;
418 
419 	int		(*enable)(struct sunxi_ccu_softc *,
420 				  struct sunxi_ccu_clk *, int);
421 	u_int		(*get_rate)(struct sunxi_ccu_softc *,
422 				    struct sunxi_ccu_clk *);
423 	int		(*set_rate)(struct sunxi_ccu_softc *,
424 				    struct sunxi_ccu_clk *, u_int);
425 	u_int		(*round_rate)(struct sunxi_ccu_softc *,
426 				    struct sunxi_ccu_clk *, u_int);
427 	const char *	(*get_parent)(struct sunxi_ccu_softc *,
428 				      struct sunxi_ccu_clk *);
429 	int		(*set_parent)(struct sunxi_ccu_softc *,
430 				      struct sunxi_ccu_clk *,
431 				      const char *);
432 };
433 
434 struct sunxi_ccu_softc {
435 	device_t		sc_dev;
436 	int			sc_phandle;
437 	bus_space_tag_t		sc_bst;
438 	bus_space_handle_t	sc_bsh;
439 
440 	struct clk_domain	sc_clkdom;
441 
442 	struct sunxi_ccu_reset *sc_resets;
443 	u_int			sc_nresets;
444 
445 	struct sunxi_ccu_clk	*sc_clks;
446 	u_int			sc_nclks;
447 };
448 
449 int	sunxi_ccu_attach(struct sunxi_ccu_softc *);
450 struct sunxi_ccu_clk *sunxi_ccu_clock_find(struct sunxi_ccu_softc *,
451 					   const char *);
452 void	sunxi_ccu_print(struct sunxi_ccu_softc *);
453 
454 #define CCU_READ(sc, reg)	\
455 	bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
456 #define CCU_WRITE(sc, reg, val)	\
457 	bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
458 
459 #endif /* _ARM_SUNXI_CCU_H */
460