imx_ccm.h revision 1.1.2.2 1 /* $NetBSD: imx_ccm.h,v 1.1.2.2 2021/01/03 16:34:52 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 2020 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_IMX_CCM_H
30 #define _ARM_IMX_CCM_H
31
32 #include <dev/clk/clk_backend.h>
33 #include <dev/fdt/syscon.h>
34
35 struct imx_ccm_softc;
36 struct imx_ccm_clk;
37
38 /*
39 * Clocks
40 */
41
42 enum imx_ccm_clktype {
43 IMX_CCM_UNKNOWN,
44 IMX_CCM_EXTCLK,
45 IMX_CCM_GATE,
46 IMX_CCM_COMPOSITE,
47 IMX_CCM_PLL,
48 IMX_CCM_FIXED,
49 IMX_CCM_FIXED_FACTOR,
50 IMX_CCM_MUX,
51 IMX_CCM_DIV,
52 };
53
54 /* External clocks */
55
56 int imx_ccm_extclk_enable(struct imx_ccm_softc *, struct imx_ccm_clk *, int);
57 u_int imx_ccm_extclk_get_rate(struct imx_ccm_softc *, struct imx_ccm_clk *);
58 int imx_ccm_extclk_set_rate(struct imx_ccm_softc *, struct imx_ccm_clk *, u_int);
59 const char *imx_ccm_extclk_get_parent(struct imx_ccm_softc *, struct imx_ccm_clk *);
60
61 #define IMX_EXTCLK(_id, _name) \
62 { \
63 .id = (_id), \
64 .type = IMX_CCM_EXTCLK, \
65 .base.name = (_name), \
66 .base.flags = 0, \
67 .u.extclk = (_name), \
68 .enable = imx_ccm_extclk_enable, \
69 .get_rate = imx_ccm_extclk_get_rate, \
70 .set_rate = imx_ccm_extclk_set_rate, \
71 .get_parent = imx_ccm_extclk_get_parent, \
72 }
73
74 /* Gate clocks */
75
76 struct imx_ccm_gate {
77 bus_size_t reg;
78 uint32_t mask;
79 const char *parent;
80 };
81
82 int imx_ccm_gate_enable(struct imx_ccm_softc *,
83 struct imx_ccm_clk *, int);
84 const char *imx_ccm_gate_get_parent(struct imx_ccm_softc *,
85 struct imx_ccm_clk *);
86
87 #define IMX_GATE(_id, _name, _pname, _reg, _mask) \
88 IMX_GATE_INDEX(_id, 0, _name, _pname, _reg, _mask)
89 #define IMX_GATE_INDEX(_id, _regidx, _name, _pname, _reg, _mask) \
90 { \
91 .id = (_id), \
92 .regidx = (_regidx), \
93 .type = IMX_CCM_GATE, \
94 .base.name = (_name), \
95 .base.flags = CLK_SET_RATE_PARENT, \
96 .u.gate.parent = (_pname), \
97 .u.gate.reg = (_reg), \
98 .u.gate.mask = (_mask), \
99 .enable = imx_ccm_gate_enable, \
100 .get_parent = imx_ccm_gate_get_parent, \
101 }
102 #define IMX_ROOT_GATE(_id, _name, _pname, _reg) \
103 IMX_ROOT_GATE_INDEX(_id, 0, _name, _pname, _reg)
104 #define IMX_ROOT_GATE_INDEX(_id, _regidx, _name, _pname, _reg) \
105 IMX_GATE_INDEX(_id, _regidx, _name, _pname, _reg, __BITS(1,0))
106
107 /* Composite clocks */
108
109 struct imx_ccm_composite {
110 bus_size_t reg;
111 const char **parents;
112 u_int nparents;
113 u_int flags;
114 #define IMX_COMPOSITE_ROUND_DOWN 0x01
115 #define IMX_COMPOSITE_SET_RATE_PARENT 0x02
116 };
117
118 int imx_ccm_composite_enable(struct imx_ccm_softc *, struct imx_ccm_clk *, int);
119 u_int imx_ccm_composite_get_rate(struct imx_ccm_softc *, struct imx_ccm_clk *);
120 int imx_ccm_composite_set_rate(struct imx_ccm_softc *, struct imx_ccm_clk *, u_int);
121 const char *imx_ccm_composite_get_parent(struct imx_ccm_softc *, struct imx_ccm_clk *);
122 int imx_ccm_composite_set_parent(struct imx_ccm_softc *, struct imx_ccm_clk *, const char *);
123
124 #define IMX_COMPOSITE(_id, _name, _parents, _reg, _flags) \
125 IMX_COMPOSITE_INDEX(_id, 0, _name, _parents, _reg, _flags)
126
127 #define IMX_COMPOSITE_INDEX(_id, _regidx, _name, _parents, _reg, _flags) \
128 { \
129 .id = (_id), \
130 .regidx = (_regidx), \
131 .type = IMX_CCM_COMPOSITE, \
132 .base.name = (_name), \
133 .base.flags = 0, \
134 .u.composite.parents = (_parents), \
135 .u.composite.nparents = __arraycount(_parents), \
136 .u.composite.reg = (_reg), \
137 .u.composite.flags = (_flags), \
138 .enable = imx_ccm_composite_enable, \
139 .get_rate = imx_ccm_composite_get_rate, \
140 .set_rate = imx_ccm_composite_set_rate, \
141 .set_parent = imx_ccm_composite_set_parent, \
142 .get_parent = imx_ccm_composite_get_parent, \
143 }
144
145 /* PLLs */
146
147 struct imx_ccm_pll {
148 bus_size_t reg;
149 const char *parent;
150 uint32_t div_mask;
151 u_int flags;
152 #define IMX_PLL_ARM __BIT(0)
153 #define IMX_PLL_480M_528M __BIT(1)
154 #define IMX_PLL_ENET __BIT(2)
155 };
156
157 int imx_ccm_pll_enable(struct imx_ccm_softc *, struct imx_ccm_clk *, int);
158 u_int imx_ccm_pll_get_rate(struct imx_ccm_softc *, struct imx_ccm_clk *);
159 const char *imx_ccm_pll_get_parent(struct imx_ccm_softc *, struct imx_ccm_clk *);
160
161 #define IMX_PLL(_id, _name, _parent, _reg, _div_mask, _flags) \
162 IMX_PLL_INDEX(_id, 0, _name, _parent, _reg, _div_mask, _flags)
163 #define IMX_PLL_INDEX(_id, _regidx, _name, _parent, _reg, _div_mask, _flags) \
164 { \
165 .id = (_id), \
166 .regidx = (_regidx), \
167 .type = IMX_CCM_PLL, \
168 .base.name = (_name), \
169 .base.flags = 0, \
170 .u.pll.parent = (_parent), \
171 .u.pll.reg = (_reg), \
172 .u.pll.div_mask = (_div_mask), \
173 .u.pll.flags = (_flags), \
174 .enable = imx_ccm_pll_enable, \
175 .get_rate = imx_ccm_pll_get_rate, \
176 .get_parent = imx_ccm_pll_get_parent, \
177 }
178
179 /* Fixed clocks */
180
181 struct imx_ccm_fixed {
182 u_int rate;
183 };
184
185 u_int imx_ccm_fixed_get_rate(struct imx_ccm_softc *, struct imx_ccm_clk *);
186
187 #define IMX_FIXED(_id, _name, _rate) \
188 { \
189 .id = (_id), \
190 .type = IMX_CCM_FIXED, \
191 .base.name = (_name), \
192 .base.flags = 0, \
193 .u.fixed.rate = (_rate), \
194 .get_rate = imx_ccm_fixed_get_rate, \
195 }
196
197 /* Fixed factor clocks */
198
199 struct imx_ccm_fixed_factor {
200 const char *parent;
201 u_int mult;
202 u_int div;
203 };
204
205 u_int imx_ccm_fixed_factor_get_rate(struct imx_ccm_softc *, struct imx_ccm_clk *);
206 int imx_ccm_fixed_factor_set_rate(struct imx_ccm_softc *, struct imx_ccm_clk *, u_int);
207 const char *imx_ccm_fixed_factor_get_parent(struct imx_ccm_softc *, struct imx_ccm_clk *);
208
209 #define IMX_FIXED_FACTOR(_id, _name, _parent, _mult, _div) \
210 { \
211 .id = (_id), \
212 .type = IMX_CCM_FIXED_FACTOR, \
213 .base.name = (_name), \
214 .base.flags = 0, \
215 .u.fixed_factor.parent = (_parent), \
216 .u.fixed_factor.mult = (_mult), \
217 .u.fixed_factor.div = (_div), \
218 .get_rate = imx_ccm_fixed_factor_get_rate, \
219 .set_rate = imx_ccm_fixed_factor_set_rate, \
220 .get_parent = imx_ccm_fixed_factor_get_parent, \
221 }
222
223 /* Mux clocks */
224
225 struct imx_ccm_mux {
226 bus_size_t reg;
227 const char **parents;
228 u_int nparents;
229 uint32_t sel;
230 };
231
232 const char *imx_ccm_mux_get_parent(struct imx_ccm_softc *, struct imx_ccm_clk *);
233 int imx_ccm_mux_set_parent(struct imx_ccm_softc *, struct imx_ccm_clk *, const char *);
234
235 #define IMX_MUX(_id, _name, _parents, _reg, _sel) \
236 IMX_MUX_INDEX(_id, 0, _name, _parents, _reg, _sel)
237
238 #define IMX_MUX_INDEX(_id, _regidx, _name, _parents, _reg, _sel) \
239 { \
240 .id = (_id), \
241 .regidx = (_regidx), \
242 .type = IMX_CCM_MUX, \
243 .base.name = (_name), \
244 .base.flags = CLK_SET_RATE_PARENT, \
245 .u.mux.parents = (_parents), \
246 .u.mux.nparents = __arraycount(_parents), \
247 .u.mux.reg = (_reg), \
248 .u.mux.sel = (_sel), \
249 .get_parent = imx_ccm_mux_get_parent, \
250 .set_parent = imx_ccm_mux_set_parent, \
251 }
252
253 /* Divider clocks */
254
255 struct imx_ccm_div {
256 bus_size_t reg;
257 const char *parent;
258 uint32_t mask;
259 u_int flags;
260 #define IMX_DIV_SET_RATE_PARENT __BIT(0)
261 #define IMX_DIV_ROUND_DOWN __BIT(1)
262 };
263
264 u_int imx_ccm_div_get_rate(struct imx_ccm_softc *, struct imx_ccm_clk *);
265 int imx_ccm_div_set_rate(struct imx_ccm_softc *, struct imx_ccm_clk *, u_int);
266 const char *imx_ccm_div_get_parent(struct imx_ccm_softc *, struct imx_ccm_clk *);
267
268 #define IMX_DIV(_id, _name, _parent, _reg, _mask, _flags) \
269 IMX_DIV_INDEX(_id, 0, _name, _parent, _reg, _mask, _flags)
270 #define IMX_DIV_INDEX(_id, _regidx, _name, _parent, _reg, _mask, _flags) \
271 { \
272 .id = (_id), \
273 .regidx = (_regidx), \
274 .type = IMX_CCM_DIV, \
275 .base.name = (_name), \
276 .base.flags = 0, \
277 .u.div.parent = (_parent), \
278 .u.div.reg = (_reg), \
279 .u.div.mask = (_mask), \
280 .u.div.flags = (_flags), \
281 .get_rate = imx_ccm_div_get_rate, \
282 .set_rate = imx_ccm_div_set_rate, \
283 .get_parent = imx_ccm_div_get_parent, \
284 }
285
286 /*
287 * IMX clock definition
288 */
289
290 struct imx_ccm_clk {
291 struct clk base;
292 u_int id;
293 u_int regidx;
294 enum imx_ccm_clktype type;
295 union {
296 struct imx_ccm_gate gate;
297 struct imx_ccm_composite composite;
298 struct imx_ccm_pll pll;
299 struct imx_ccm_fixed fixed;
300 struct imx_ccm_fixed_factor fixed_factor;
301 struct imx_ccm_mux mux;
302 struct imx_ccm_div div;
303 const char *extclk;
304 } u;
305
306 int (*enable)(struct imx_ccm_softc *,
307 struct imx_ccm_clk *, int);
308 u_int (*get_rate)(struct imx_ccm_softc *,
309 struct imx_ccm_clk *);
310 int (*set_rate)(struct imx_ccm_softc *,
311 struct imx_ccm_clk *, u_int);
312 u_int (*round_rate)(struct imx_ccm_softc *,
313 struct imx_ccm_clk *, u_int);
314 const char * (*get_parent)(struct imx_ccm_softc *,
315 struct imx_ccm_clk *);
316 int (*set_parent)(struct imx_ccm_softc *,
317 struct imx_ccm_clk *,
318 const char *);
319 };
320
321 /*
322 * Driver state
323 */
324
325 struct imx_ccm_softc {
326 device_t sc_dev;
327 int sc_phandle;
328 bus_space_tag_t sc_bst;
329 bus_space_handle_t sc_bsh[2];
330
331 bus_addr_t sc_baseaddr;
332
333 struct clk_domain sc_clkdom;
334
335 struct imx_ccm_clk *sc_clks;
336 u_int sc_nclks;
337 };
338
339 int imx_ccm_attach(struct imx_ccm_softc *);
340 struct imx_ccm_clk *imx_ccm_clock_find(struct imx_ccm_softc *,
341 const char *);
342 void imx_ccm_print(struct imx_ccm_softc *);
343
344 extern const struct clk_funcs imx_ccm_clock_funcs;
345
346 #define CCM_READ(sc, idx, reg) \
347 bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh[idx], (reg))
348 #define CCM_WRITE(sc, idx, reg, val) \
349 bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh[idx], (reg), (val))
350
351 #endif /* _ARM_IMX_CCM_H */
352