sunxi_ccu.h revision 1.15
1/* $NetBSD: sunxi_ccu.h,v 1.15 2017/10/28 13:13:45 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
34struct sunxi_ccu_softc;
35struct sunxi_ccu_clk;
36struct sunxi_ccu_reset;
37
38/*
39 * Resets
40 */
41
42struct 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
57enum 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};
67
68struct sunxi_ccu_gate {
69	bus_size_t	reg;
70	uint32_t	mask;
71	const char	*parent;
72};
73
74int	sunxi_ccu_gate_enable(struct sunxi_ccu_softc *,
75			      struct sunxi_ccu_clk *, int);
76const char *sunxi_ccu_gate_get_parent(struct sunxi_ccu_softc *,
77				      struct sunxi_ccu_clk *);
78
79#define	SUNXI_CCU_GATE(_id, _name, _pname, _reg, _bit)		\
80	[_id] = {						\
81		.type = SUNXI_CCU_GATE,				\
82		.base.name = (_name),				\
83		.base.flags = CLK_SET_RATE_PARENT,		\
84		.u.gate.parent = (_pname),			\
85		.u.gate.reg = (_reg),				\
86		.u.gate.mask = __BIT(_bit),			\
87		.enable = sunxi_ccu_gate_enable,		\
88		.get_parent = sunxi_ccu_gate_get_parent,	\
89	}
90
91struct sunxi_ccu_nkmp_tbl {
92	u_int		rate;
93	uint32_t	n;
94	uint32_t	k;
95	uint32_t	m;
96	uint32_t	p;
97};
98
99struct sunxi_ccu_nkmp {
100	bus_size_t	reg;
101	const char	*parent;
102	uint32_t	n;
103	uint32_t	k;
104	uint32_t	m;
105	uint32_t	p;
106	uint32_t	lock;
107	uint32_t	enable;
108	uint32_t	flags;
109	const struct sunxi_ccu_nkmp_tbl *table;
110#define	SUNXI_CCU_NKMP_DIVIDE_BY_TWO		__BIT(0)
111#define	SUNXI_CCU_NKMP_FACTOR_N_EXACT		__BIT(1)
112#define	SUNXI_CCU_NKMP_SCALE_CLOCK		__BIT(2)
113#define	SUNXI_CCU_NKMP_FACTOR_P_POW2		__BIT(3)
114#define	SUNXI_CCU_NKMP_FACTOR_N_ZERO_IS_ONE	__BIT(4)
115};
116
117int	sunxi_ccu_nkmp_enable(struct sunxi_ccu_softc *,
118			      struct sunxi_ccu_clk *, int);
119u_int	sunxi_ccu_nkmp_get_rate(struct sunxi_ccu_softc *,
120				struct sunxi_ccu_clk *);
121int	sunxi_ccu_nkmp_set_rate(struct sunxi_ccu_softc *,
122				struct sunxi_ccu_clk *, u_int);
123const char *sunxi_ccu_nkmp_get_parent(struct sunxi_ccu_softc *,
124				      struct sunxi_ccu_clk *);
125
126#define	SUNXI_CCU_NKMP_TABLE(_id, _name, _parent, _reg, _n, _k, _m, \
127		       _p, _enable, _lock, _tbl, _flags)	\
128	[_id] = {						\
129		.type = SUNXI_CCU_NKMP,				\
130		.base.name = (_name),				\
131		.u.nkmp.reg = (_reg),				\
132		.u.nkmp.parent = (_parent),			\
133		.u.nkmp.n = (_n),				\
134		.u.nkmp.k = (_k),				\
135		.u.nkmp.m = (_m),				\
136		.u.nkmp.p = (_p),				\
137		.u.nkmp.enable = (_enable),			\
138		.u.nkmp.flags = (_flags),			\
139		.u.nkmp.lock = (_lock),				\
140		.u.nkmp.table = (_tbl),				\
141		.enable = sunxi_ccu_nkmp_enable,		\
142		.get_rate = sunxi_ccu_nkmp_get_rate,		\
143		.set_rate = sunxi_ccu_nkmp_set_rate,		\
144		.get_parent = sunxi_ccu_nkmp_get_parent,	\
145	}
146
147#define	SUNXI_CCU_NKMP(_id, _name, _parent, _reg, _n, _k, _m,	\
148		       _p, _enable, _flags)			\
149	SUNXI_CCU_NKMP_TABLE(_id, _name, _parent, _reg, _n, _k, _m, \
150			     _p, _enable, 0, NULL, _flags)
151
152
153struct sunxi_ccu_nm {
154	bus_size_t	reg;
155	const char	**parents;
156	u_int		nparents;
157	uint32_t	n;
158	uint32_t	m;
159	uint32_t	sel;
160	uint32_t	enable;
161	uint32_t	flags;
162#define	SUNXI_CCU_NM_POWER_OF_TWO	__BIT(0)
163#define	SUNXI_CCU_NM_ROUND_DOWN		__BIT(1)
164#define	SUNXI_CCU_NM_DIVIDE_BY_TWO	__BIT(2)
165};
166
167int	sunxi_ccu_nm_enable(struct sunxi_ccu_softc *,
168			    struct sunxi_ccu_clk *, int);
169u_int	sunxi_ccu_nm_get_rate(struct sunxi_ccu_softc *,
170			      struct sunxi_ccu_clk *);
171int	sunxi_ccu_nm_set_rate(struct sunxi_ccu_softc *,
172			      struct sunxi_ccu_clk *, u_int);
173int	sunxi_ccu_nm_set_parent(struct sunxi_ccu_softc *,
174				struct sunxi_ccu_clk *,
175				const char *);
176const char *sunxi_ccu_nm_get_parent(struct sunxi_ccu_softc *,
177				    struct sunxi_ccu_clk *);
178
179#define	SUNXI_CCU_NM(_id, _name, _parents, _reg, _n, _m, _sel,	\
180		     _enable, _flags)				\
181	[_id] = {						\
182		.type = SUNXI_CCU_NM,				\
183		.base.name = (_name),				\
184		.u.nm.reg = (_reg),				\
185		.u.nm.parents = (_parents),			\
186		.u.nm.nparents = __arraycount(_parents),	\
187		.u.nm.n = (_n),					\
188		.u.nm.m = (_m),					\
189		.u.nm.sel = (_sel),				\
190		.u.nm.enable = (_enable),			\
191		.u.nm.flags = (_flags),				\
192		.enable = sunxi_ccu_nm_enable,			\
193		.get_rate = sunxi_ccu_nm_get_rate,		\
194		.set_rate = sunxi_ccu_nm_set_rate,		\
195		.set_parent = sunxi_ccu_nm_set_parent,		\
196		.get_parent = sunxi_ccu_nm_get_parent,		\
197	}
198
199struct sunxi_ccu_div {
200	bus_size_t	reg;
201	const char	**parents;
202	u_int		nparents;
203	uint32_t	div;
204	uint32_t	sel;
205	uint32_t	enable;
206	uint32_t	flags;
207#define	SUNXI_CCU_DIV_POWER_OF_TWO	__BIT(0)
208#define	SUNXI_CCU_DIV_ZERO_IS_ONE	__BIT(1)
209#define	SUNXI_CCU_DIV_TIMES_TWO		__BIT(2)
210#define	SUNXI_CCU_DIV_SET_RATE_PARENT	__BIT(3)
211};
212
213int	sunxi_ccu_div_enable(struct sunxi_ccu_softc *,
214			     struct sunxi_ccu_clk *, int);
215u_int	sunxi_ccu_div_get_rate(struct sunxi_ccu_softc *,
216			       struct sunxi_ccu_clk *);
217int	sunxi_ccu_div_set_rate(struct sunxi_ccu_softc *,
218			       struct sunxi_ccu_clk *, u_int);
219int	sunxi_ccu_div_set_parent(struct sunxi_ccu_softc *,
220			         struct sunxi_ccu_clk *,
221			         const char *);
222const char *sunxi_ccu_div_get_parent(struct sunxi_ccu_softc *,
223				     struct sunxi_ccu_clk *);
224
225#define	SUNXI_CCU_DIV(_id, _name, _parents, _reg, _div,		\
226		      _sel, _flags)				\
227	SUNXI_CCU_DIV_GATE(_id, _name, _parents, _reg, _div,	\
228			   _sel, 0, _flags)
229
230#define	SUNXI_CCU_DIV_GATE(_id, _name, _parents, _reg, _div,	\
231		      _sel, _enable, _flags)			\
232	[_id] = {						\
233		.type = SUNXI_CCU_DIV,				\
234		.base.name = (_name),				\
235		.u.div.reg = (_reg),				\
236		.u.div.parents = (_parents),			\
237		.u.div.nparents = __arraycount(_parents),	\
238		.u.div.div = (_div),				\
239		.u.div.sel = (_sel),				\
240		.u.div.enable = (_enable),			\
241		.u.div.flags = (_flags),			\
242		.enable = sunxi_ccu_div_enable,			\
243		.get_rate = sunxi_ccu_div_get_rate,		\
244		.set_rate = sunxi_ccu_div_set_rate,		\
245		.set_parent = sunxi_ccu_div_set_parent,		\
246		.get_parent = sunxi_ccu_div_get_parent,		\
247	}
248
249struct sunxi_ccu_prediv {
250	bus_size_t	reg;
251	const char	**parents;
252	u_int		nparents;
253	uint32_t	prediv;
254	uint32_t	prediv_sel;
255	uint32_t	prediv_fixed;
256	uint32_t	div;
257	uint32_t	sel;
258	uint32_t	flags;
259#define	SUNXI_CCU_PREDIV_POWER_OF_TWO	__BIT(0)
260#define	SUNXI_CCU_PREDIV_DIVIDE_BY_TWO	__BIT(1)
261};
262
263u_int	sunxi_ccu_prediv_get_rate(struct sunxi_ccu_softc *,
264				  struct sunxi_ccu_clk *);
265int	sunxi_ccu_prediv_set_rate(struct sunxi_ccu_softc *,
266				  struct sunxi_ccu_clk *, u_int);
267int	sunxi_ccu_prediv_set_parent(struct sunxi_ccu_softc *,
268				    struct sunxi_ccu_clk *,
269				    const char *);
270const char *sunxi_ccu_prediv_get_parent(struct sunxi_ccu_softc *,
271					struct sunxi_ccu_clk *);
272
273#define	SUNXI_CCU_PREDIV(_id, _name, _parents, _reg, _prediv,	\
274		     _prediv_sel, _div, _sel, _flags)		\
275	SUNXI_CCU_PREDIV_FIXED(_id, _name, _parents, _reg, _prediv, \
276		     _prediv_sel, 0, _div, _sel, _flags)
277
278#define	SUNXI_CCU_PREDIV_FIXED(_id, _name, _parents, _reg, _prediv, \
279		     _prediv_sel, _prediv_fixed, _div, _sel, _flags) \
280	[_id] = {						\
281		.type = SUNXI_CCU_PREDIV,			\
282		.base.name = (_name),				\
283		.u.prediv.reg = (_reg),				\
284		.u.prediv.parents = (_parents),			\
285		.u.prediv.nparents = __arraycount(_parents),	\
286		.u.prediv.prediv = (_prediv),			\
287		.u.prediv.prediv_sel = (_prediv_sel),		\
288		.u.prediv.prediv_fixed = (_prediv_fixed),	\
289		.u.prediv.div = (_div),				\
290		.u.prediv.sel = (_sel),				\
291		.u.prediv.flags = (_flags),			\
292		.get_rate = sunxi_ccu_prediv_get_rate,		\
293		.set_rate = sunxi_ccu_prediv_set_rate,		\
294		.set_parent = sunxi_ccu_prediv_set_parent,	\
295		.get_parent = sunxi_ccu_prediv_get_parent,	\
296	}
297
298struct sunxi_ccu_phase {
299	bus_size_t	reg;
300	const char	*parent;
301	uint32_t	mask;
302};
303
304u_int	sunxi_ccu_phase_get_rate(struct sunxi_ccu_softc *,
305				 struct sunxi_ccu_clk *);
306int	sunxi_ccu_phase_set_rate(struct sunxi_ccu_softc *,
307				 struct sunxi_ccu_clk *, u_int);
308const char *sunxi_ccu_phase_get_parent(struct sunxi_ccu_softc *,
309				       struct sunxi_ccu_clk *);
310
311#define	SUNXI_CCU_PHASE(_id, _name, _parent, _reg, _mask)	\
312	[_id] = {						\
313		.type = SUNXI_CCU_PHASE,			\
314		.base.name = (_name),				\
315		.u.phase.reg = (_reg),				\
316		.u.phase.parent = (_parent),			\
317		.u.phase.mask = (_mask),			\
318		.get_rate = sunxi_ccu_phase_get_rate,		\
319		.set_rate = sunxi_ccu_phase_set_rate,		\
320		.get_parent = sunxi_ccu_phase_get_parent,	\
321	}
322
323struct sunxi_ccu_fixed_factor {
324	const char	*parent;
325	u_int		div;
326	u_int		mult;
327};
328
329u_int	sunxi_ccu_fixed_factor_get_rate(struct sunxi_ccu_softc *,
330					struct sunxi_ccu_clk *);
331const char *sunxi_ccu_fixed_factor_get_parent(struct sunxi_ccu_softc *,
332					      struct sunxi_ccu_clk *);
333
334#define	SUNXI_CCU_FIXED_FACTOR(_id, _name, _parent, _div, _mult)	\
335	[_id] = {							\
336		.type = SUNXI_CCU_FIXED_FACTOR,				\
337		.base.name = (_name),					\
338		.u.fixed_factor.parent = (_parent),			\
339		.u.fixed_factor.div = (_div),				\
340		.u.fixed_factor.mult = (_mult),				\
341		.get_rate = sunxi_ccu_fixed_factor_get_rate,		\
342		.get_parent = sunxi_ccu_fixed_factor_get_parent,	\
343	}
344
345struct sunxi_ccu_clk {
346	struct clk	base;
347	enum sunxi_ccu_clktype type;
348	union {
349		struct sunxi_ccu_gate gate;
350		struct sunxi_ccu_nm nm;
351		struct sunxi_ccu_nkmp nkmp;
352		struct sunxi_ccu_prediv prediv;
353		struct sunxi_ccu_div div;
354		struct sunxi_ccu_phase phase;
355		struct sunxi_ccu_fixed_factor fixed_factor;
356	} u;
357
358	int		(*enable)(struct sunxi_ccu_softc *,
359				  struct sunxi_ccu_clk *, int);
360	u_int		(*get_rate)(struct sunxi_ccu_softc *,
361				    struct sunxi_ccu_clk *);
362	int		(*set_rate)(struct sunxi_ccu_softc *,
363				    struct sunxi_ccu_clk *, u_int);
364	const char *	(*get_parent)(struct sunxi_ccu_softc *,
365				      struct sunxi_ccu_clk *);
366	int		(*set_parent)(struct sunxi_ccu_softc *,
367				      struct sunxi_ccu_clk *,
368				      const char *);
369};
370
371struct sunxi_ccu_softc {
372	device_t		sc_dev;
373	int			sc_phandle;
374	bus_space_tag_t		sc_bst;
375	bus_space_handle_t	sc_bsh;
376
377	struct clk_domain	sc_clkdom;
378
379	struct sunxi_ccu_reset *sc_resets;
380	u_int			sc_nresets;
381
382	struct sunxi_ccu_clk	*sc_clks;
383	u_int			sc_nclks;
384};
385
386int	sunxi_ccu_attach(struct sunxi_ccu_softc *);
387struct sunxi_ccu_clk *sunxi_ccu_clock_find(struct sunxi_ccu_softc *,
388					   const char *);
389void	sunxi_ccu_print(struct sunxi_ccu_softc *);
390
391#define CCU_READ(sc, reg)	\
392	bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
393#define CCU_WRITE(sc, reg, val)	\
394	bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
395
396#endif /* _ARM_SUNXI_CCU_H */
397