1/* $NetBSD: meson_clk.h,v 1.4 2021/01/01 07:21:58 ryo Exp $ */
2
3/*-
4 * Copyright (c) 2017-2019 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_MESON_CLK_H
30#define _ARM_MESON_CLK_H
31
32#include <dev/clk/clk_backend.h>
33#include <dev/fdt/syscon.h>
34
35struct meson_clk_softc;
36struct meson_clk_clk;
37struct meson_clk_reset;
38
39/*
40 * Resets
41 */
42
43struct meson_clk_reset {
44	bus_size_t	reg;
45	uint32_t	mask;
46};
47
48#define	MESON_CLK_RESET(_id, _reg, _bit)	\
49	[_id] = {				\
50		.reg = (_reg),			\
51		.mask = __BIT(_bit),		\
52	}
53
54/*
55 * Clocks
56 */
57
58enum meson_clk_clktype {
59	MESON_CLK_UNKNOWN,
60	MESON_CLK_FIXED,
61	MESON_CLK_GATE,
62	MESON_CLK_PLL,
63	MESON_CLK_MPLL,
64	MESON_CLK_DIV,
65	MESON_CLK_FIXED_FACTOR,
66	MESON_CLK_MUX,
67};
68
69/*
70 * Fixed clocks
71 */
72
73struct meson_clk_fixed {
74	u_int		rate;
75};
76
77u_int	meson_clk_fixed_get_rate(struct meson_clk_softc *, struct meson_clk_clk *);
78
79#define	MESON_CLK_FIXED(_id, _name, _rate)			\
80	[_id] = {						\
81		.type = MESON_CLK_FIXED,			\
82		.base.name = (_name),				\
83		.base.flags = 0,				\
84		.u.fixed.rate = (_rate),			\
85		.get_rate = meson_clk_fixed_get_rate,		\
86	}
87
88/*
89 * Gate clocks
90 */
91
92struct meson_clk_gate {
93	bus_size_t	reg;
94	uint32_t	mask;
95	const char	*parent;
96	uint32_t	flags;
97#define	MESON_CLK_GATE_SET_TO_DISABLE		__BIT(0)
98};
99
100int	meson_clk_gate_enable(struct meson_clk_softc *,
101			      struct meson_clk_clk *, int);
102const char *meson_clk_gate_get_parent(struct meson_clk_softc *,
103				      struct meson_clk_clk *);
104
105#define	MESON_CLK_GATE_FLAGS(_id, _name, _pname, _reg, _bit, _flags)	\
106	[_id] = {						\
107		.type = MESON_CLK_GATE,				\
108		.base.name = (_name),				\
109		.base.flags = CLK_SET_RATE_PARENT,		\
110		.u.gate.parent = (_pname),			\
111		.u.gate.reg = (_reg),				\
112		.u.gate.mask = __BIT(_bit),			\
113		.u.gate.flags = (_flags),			\
114		.enable = meson_clk_gate_enable,		\
115		.get_parent = meson_clk_gate_get_parent,	\
116	}
117
118#define	MESON_CLK_GATE(_id, _name, _pname, _reg, _bit)		\
119	MESON_CLK_GATE_FLAGS(_id, _name, _pname, _reg, _bit, 0)
120
121/*
122 * Divider clocks
123 */
124
125struct meson_clk_div {
126	bus_size_t	reg;
127	const char	*parent;
128	uint32_t	div;
129	uint32_t	flags;
130#define	MESON_CLK_DIV_POWER_OF_TWO	__BIT(0)
131#define	MESON_CLK_DIV_SET_RATE_PARENT	__BIT(1)
132#define	MESON_CLK_DIV_CPU_SCALE_TABLE	__BIT(2)
133};
134
135u_int	meson_clk_div_get_rate(struct meson_clk_softc *,
136			       struct meson_clk_clk *);
137int	meson_clk_div_set_rate(struct meson_clk_softc *,
138			       struct meson_clk_clk *, u_int);
139const char *meson_clk_div_get_parent(struct meson_clk_softc *,
140				     struct meson_clk_clk *);
141
142#define	MESON_CLK_DIV(_id, _name, _parent, _reg, _div, _flags)	\
143	[_id] = {						\
144		.type = MESON_CLK_DIV,				\
145		.base.name = (_name),				\
146		.u.div.reg = (_reg),				\
147		.u.div.parent = (_parent),			\
148		.u.div.div = (_div),				\
149		.u.div.flags = (_flags),			\
150		.get_rate = meson_clk_div_get_rate,		\
151		.set_rate = meson_clk_div_set_rate,		\
152		.get_parent = meson_clk_div_get_parent,		\
153	}
154
155/*
156 * Fixed-factor clocks
157 */
158
159struct meson_clk_fixed_factor {
160	const char	*parent;
161	u_int		div;
162	u_int		mult;
163};
164
165u_int	meson_clk_fixed_factor_get_rate(struct meson_clk_softc *,
166					struct meson_clk_clk *);
167int	meson_clk_fixed_factor_set_rate(struct meson_clk_softc *,
168					struct meson_clk_clk *, u_int);
169const char *meson_clk_fixed_factor_get_parent(struct meson_clk_softc *,
170					      struct meson_clk_clk *);
171
172#define	MESON_CLK_FIXED_FACTOR(_id, _name, _parent, _div, _mult)	\
173	[_id] = {							\
174		.type = MESON_CLK_FIXED_FACTOR,				\
175		.base.name = (_name),					\
176		.u.fixed_factor.parent = (_parent),			\
177		.u.fixed_factor.div = (_div),				\
178		.u.fixed_factor.mult = (_mult),				\
179		.get_rate = meson_clk_fixed_factor_get_rate,		\
180		.get_parent = meson_clk_fixed_factor_get_parent,	\
181		.set_rate = meson_clk_fixed_factor_set_rate,		\
182	}
183
184/*
185 * Mux clocks
186 */
187
188struct meson_clk_mux {
189	bus_size_t	reg;
190	const char	**parents;
191	u_int		nparents;
192	uint32_t	sel;
193	uint32_t	flags;
194};
195
196const char *meson_clk_mux_get_parent(struct meson_clk_softc *,
197			       struct meson_clk_clk *);
198
199#define	MESON_CLK_MUX_RATE(_id, _name, _parents, _reg, _sel,		\
200			   _getratefn, _setratefn, _flags)		\
201	[_id] = {							\
202		.type = MESON_CLK_MUX,					\
203		.base.name = (_name),					\
204		.base.flags = 0,					\
205		.u.mux.parents = (_parents),				\
206		.u.mux.nparents = __arraycount(_parents),		\
207		.u.mux.reg = (_reg),					\
208		.u.mux.sel = (_sel),					\
209		.u.mux.flags = (_flags),				\
210		.get_rate = _getratefn,					\
211		.set_rate = _setratefn,					\
212		.get_parent = meson_clk_mux_get_parent,			\
213	}
214
215#define	MESON_CLK_MUX(_id, _name, _parents, _reg, _sel, _flags)		\
216	[_id] = {							\
217		.type = MESON_CLK_MUX,					\
218		.base.name = (_name),					\
219		.base.flags = CLK_SET_RATE_PARENT,			\
220		.u.mux.parents = (_parents),				\
221		.u.mux.nparents = __arraycount(_parents),		\
222		.u.mux.reg = (_reg),					\
223		.u.mux.sel = (_sel),					\
224		.u.mux.flags = (_flags),				\
225		.get_parent = meson_clk_mux_get_parent,			\
226	}
227
228/*
229 * PLL clocks
230 */
231
232struct meson_clk_pll_reg {
233	bus_size_t	reg;
234	uint32_t	mask;
235};
236
237#define	MESON_CLK_PLL_REG(_reg, _mask)					\
238	{ .reg = (_reg), .mask = (_mask) }
239#define	MESON_CLK_PLL_REG_INVALID	MESON_CLK_PLL_REG(0,0)
240
241struct meson_clk_pll {
242	struct meson_clk_pll_reg	enable;
243	struct meson_clk_pll_reg	m;
244	struct meson_clk_pll_reg	n;
245	struct meson_clk_pll_reg	frac;
246	struct meson_clk_pll_reg	l;
247	struct meson_clk_pll_reg	reset;
248	const char			*parent;
249	uint32_t			flags;
250};
251
252u_int	meson_clk_pll_get_rate(struct meson_clk_softc *,
253			       struct meson_clk_clk *);
254int	meson_clk_pll_set_rate(struct meson_clk_softc *,
255			       struct meson_clk_clk *, u_int new_rate);
256const char *meson_clk_pll_get_parent(struct meson_clk_softc *,
257				     struct meson_clk_clk *);
258int	meson_clk_pll_wait_lock(struct meson_clk_softc *sc,
259				struct meson_clk_pll *pll);
260
261
262#define	MESON_CLK_PLL_RATE(_id, _name, _parent, _enable, _m, _n, _frac, _l,	\
263		      _reset, _setratefn, _flags)			\
264	[_id] = {							\
265		.type = MESON_CLK_PLL,					\
266		.base.name = (_name),					\
267		.u.pll.parent = (_parent),				\
268		.u.pll.enable = _enable,				\
269		.u.pll.m = _m,						\
270		.u.pll.n = _n,						\
271		.u.pll.frac = _frac,					\
272		.u.pll.l = _l,						\
273		.u.pll.reset = _reset,					\
274		.u.pll.flags = (_flags),				\
275		.set_rate = (_setratefn),				\
276		.get_rate = meson_clk_pll_get_rate,			\
277		.get_parent = meson_clk_pll_get_parent,			\
278	}
279
280#define	MESON_CLK_PLL(_id, _name, _parent, _enable, _m, _n, _frac, _l,	\
281		      _reset, _flags)					\
282	[_id] = {							\
283		.type = MESON_CLK_PLL,					\
284		.base.name = (_name),					\
285		.u.pll.parent = (_parent),				\
286		.u.pll.enable = _enable,				\
287		.u.pll.m = _m,						\
288		.u.pll.n = _n,						\
289		.u.pll.frac = _frac,					\
290		.u.pll.l = _l,						\
291		.u.pll.reset = _reset,					\
292		.u.pll.flags = (_flags),				\
293		.get_rate = meson_clk_pll_get_rate,			\
294		.get_parent = meson_clk_pll_get_parent,			\
295	}
296
297/*
298 * MPLL clocks
299 */
300
301struct meson_clk_mpll {
302	struct meson_clk_pll_reg	sdm;
303	struct meson_clk_pll_reg	sdm_enable;
304	struct meson_clk_pll_reg	n2;
305	struct meson_clk_pll_reg	ssen;
306	const char			*parent;
307	uint32_t			flags;
308};
309
310u_int	meson_clk_mpll_get_rate(struct meson_clk_softc *,
311				struct meson_clk_clk *);
312const char *meson_clk_mpll_get_parent(struct meson_clk_softc *,
313				      struct meson_clk_clk *);
314
315#define	MESON_CLK_MPLL(_id, _name, _parent, _sdm, _sdm_enable, _n2,	\
316		       _ssen, _flags)					\
317	[_id] = {							\
318		.type = MESON_CLK_MPLL,					\
319		.base.name = (_name),					\
320		.u.mpll.parent = (_parent),				\
321		.u.mpll.sdm = _sdm,					\
322		.u.mpll.sdm_enable = _sdm_enable,			\
323		.u.mpll.n2 = _n2,					\
324		.u.mpll.ssen = _ssen,					\
325		.u.mpll.flags = (_flags),				\
326		.get_rate = meson_clk_mpll_get_rate,			\
327		.get_parent = meson_clk_mpll_get_parent,		\
328	}
329
330
331
332struct meson_clk_clk {
333	struct clk	base;
334	enum meson_clk_clktype type;
335	union {
336		struct meson_clk_fixed fixed;
337		struct meson_clk_gate gate;
338		struct meson_clk_div div;
339		struct meson_clk_fixed_factor fixed_factor;
340		struct meson_clk_mux mux;
341		struct meson_clk_pll pll;
342		struct meson_clk_mpll mpll;
343	} u;
344
345	int		(*enable)(struct meson_clk_softc *,
346				  struct meson_clk_clk *, int);
347	u_int		(*get_rate)(struct meson_clk_softc *,
348				    struct meson_clk_clk *);
349	int		(*set_rate)(struct meson_clk_softc *,
350				    struct meson_clk_clk *, u_int);
351	u_int		(*round_rate)(struct meson_clk_softc *,
352				    struct meson_clk_clk *, u_int);
353	const char *	(*get_parent)(struct meson_clk_softc *,
354				      struct meson_clk_clk *);
355	int		(*set_parent)(struct meson_clk_softc *,
356				      struct meson_clk_clk *,
357				      const char *);
358};
359
360struct meson_clk_softc {
361	device_t		sc_dev;
362	int			sc_phandle;
363
364	bus_space_tag_t		sc_bst;
365	bus_space_handle_t	sc_bsh;
366
367	struct syscon		*sc_syscon;
368
369	struct clk_domain	sc_clkdom;
370
371	struct meson_clk_reset *sc_resets;
372	u_int			sc_nresets;
373
374	struct meson_clk_clk	*sc_clks;
375	u_int			sc_nclks;
376};
377
378void	meson_clk_attach(struct meson_clk_softc *);
379struct meson_clk_clk *meson_clk_clock_find(struct meson_clk_softc *,
380					   const char *);
381void	meson_clk_print(struct meson_clk_softc *);
382
383void	meson_clk_lock(struct meson_clk_softc *);
384void	meson_clk_unlock(struct meson_clk_softc *);
385uint32_t meson_clk_read(struct meson_clk_softc *, bus_size_t);
386void	meson_clk_write(struct meson_clk_softc *, bus_size_t, uint32_t);
387
388#define	CLK_LOCK	meson_clk_lock
389#define	CLK_UNLOCK	meson_clk_unlock
390#define	CLK_READ	meson_clk_read
391#define	CLK_WRITE	meson_clk_write
392#define CLK_WRITE_BITS(sc, reg, mask, val)			\
393	do {							\
394		uint32_t _cwb_tmp_ = CLK_READ((sc), (reg));	\
395		_cwb_tmp_ &= ~(mask);				\
396		_cwb_tmp_ |= __SHIFTIN((val), (mask));		\
397		CLK_WRITE((sc), (reg), _cwb_tmp_);		\
398	} while (0 /*CONSTCOND*/)
399
400#endif /* _ARM_MESON_CLK_H */
401