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