sunxi_ccu.h revision 1.5 1 /* $NetBSD: sunxi_ccu.h,v 1.5 2017/07/02 00:14:09 jmcneill Exp $ */
2
3 /*-
4 * Copyright (c) 2017 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_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 };
65
66 struct sunxi_ccu_gate {
67 bus_size_t reg;
68 uint32_t mask;
69 const char *parent;
70 };
71
72 int sunxi_ccu_gate_enable(struct sunxi_ccu_softc *,
73 struct sunxi_ccu_clk *, int);
74 const char *sunxi_ccu_gate_get_parent(struct sunxi_ccu_softc *,
75 struct sunxi_ccu_clk *);
76
77 #define SUNXI_CCU_GATE(_id, _name, _pname, _reg, _bit) \
78 [_id] = { \
79 .type = SUNXI_CCU_GATE, \
80 .base.name = (_name), \
81 .u.gate.parent = (_pname), \
82 .u.gate.reg = (_reg), \
83 .u.gate.mask = __BIT(_bit), \
84 .enable = sunxi_ccu_gate_enable, \
85 .get_parent = sunxi_ccu_gate_get_parent, \
86 }
87
88 struct sunxi_ccu_nkmp {
89 bus_size_t reg;
90 const char *parent;
91 uint32_t n;
92 uint32_t k;
93 uint32_t m;
94 uint32_t p;
95 uint32_t lock;
96 uint32_t enable;
97 uint32_t flags;
98 #define SUNXI_CCU_NKMP_DIVIDE_BY_TWO __BIT(0)
99 };
100
101 int sunxi_ccu_nkmp_enable(struct sunxi_ccu_softc *,
102 struct sunxi_ccu_clk *, int);
103 u_int sunxi_ccu_nkmp_get_rate(struct sunxi_ccu_softc *,
104 struct sunxi_ccu_clk *);
105 int sunxi_ccu_nkmp_set_rate(struct sunxi_ccu_softc *,
106 struct sunxi_ccu_clk *, u_int);
107 const char *sunxi_ccu_nkmp_get_parent(struct sunxi_ccu_softc *,
108 struct sunxi_ccu_clk *);
109
110 #define SUNXI_CCU_NKMP(_id, _name, _parent, _reg, _n, _k, _m, \
111 _p, _enable, _flags) \
112 [_id] = { \
113 .type = SUNXI_CCU_NKMP, \
114 .base.name = (_name), \
115 .u.nkmp.reg = (_reg), \
116 .u.nkmp.parent = (_parent), \
117 .u.nkmp.n = (_n), \
118 .u.nkmp.k = (_k), \
119 .u.nkmp.m = (_m), \
120 .u.nkmp.p = (_p), \
121 .u.nkmp.enable = (_enable), \
122 .u.nkmp.flags = (_flags), \
123 .enable = sunxi_ccu_nkmp_enable, \
124 .get_rate = sunxi_ccu_nkmp_get_rate, \
125 .set_rate = sunxi_ccu_nkmp_set_rate, \
126 .get_parent = sunxi_ccu_nkmp_get_parent, \
127 }
128
129 struct sunxi_ccu_nm {
130 bus_size_t reg;
131 const char **parents;
132 u_int nparents;
133 uint32_t n;
134 uint32_t m;
135 uint32_t sel;
136 uint32_t enable;
137 uint32_t flags;
138 #define SUNXI_CCU_NM_POWER_OF_TWO __BIT(0)
139 #define SUNXI_CCU_NM_ROUND_DOWN __BIT(1)
140 };
141
142 int sunxi_ccu_nm_enable(struct sunxi_ccu_softc *,
143 struct sunxi_ccu_clk *, int);
144 u_int sunxi_ccu_nm_get_rate(struct sunxi_ccu_softc *,
145 struct sunxi_ccu_clk *);
146 int sunxi_ccu_nm_set_rate(struct sunxi_ccu_softc *,
147 struct sunxi_ccu_clk *, u_int);
148 int sunxi_ccu_nm_set_parent(struct sunxi_ccu_softc *,
149 struct sunxi_ccu_clk *,
150 const char *);
151 const char *sunxi_ccu_nm_get_parent(struct sunxi_ccu_softc *,
152 struct sunxi_ccu_clk *);
153
154 #define SUNXI_CCU_NM(_id, _name, _parents, _reg, _n, _m, _sel, \
155 _enable, _flags) \
156 [_id] = { \
157 .type = SUNXI_CCU_NM, \
158 .base.name = (_name), \
159 .u.nm.reg = (_reg), \
160 .u.nm.parents = (_parents), \
161 .u.nm.nparents = __arraycount(_parents), \
162 .u.nm.n = (_n), \
163 .u.nm.m = (_m), \
164 .u.nm.sel = (_sel), \
165 .u.nm.enable = (_enable), \
166 .u.nm.flags = (_flags), \
167 .enable = sunxi_ccu_nm_enable, \
168 .get_rate = sunxi_ccu_nm_get_rate, \
169 .set_rate = sunxi_ccu_nm_set_rate, \
170 .set_parent = sunxi_ccu_nm_set_parent, \
171 .get_parent = sunxi_ccu_nm_get_parent, \
172 }
173
174 struct sunxi_ccu_div {
175 bus_size_t reg;
176 const char **parents;
177 u_int nparents;
178 uint32_t div;
179 uint32_t sel;
180 uint32_t flags;
181 #define SUNXI_CCU_DIV_POWER_OF_TWO __BIT(0)
182 #define SUNXI_CCU_DIV_ZERO_IS_ONE __BIT(1)
183 };
184
185 u_int sunxi_ccu_div_get_rate(struct sunxi_ccu_softc *,
186 struct sunxi_ccu_clk *);
187 int sunxi_ccu_div_set_rate(struct sunxi_ccu_softc *,
188 struct sunxi_ccu_clk *, u_int);
189 int sunxi_ccu_div_set_parent(struct sunxi_ccu_softc *,
190 struct sunxi_ccu_clk *,
191 const char *);
192 const char *sunxi_ccu_div_get_parent(struct sunxi_ccu_softc *,
193 struct sunxi_ccu_clk *);
194
195 #define SUNXI_CCU_DIV(_id, _name, _parents, _reg, _div, \
196 _sel, _flags) \
197 [_id] = { \
198 .type = SUNXI_CCU_DIV, \
199 .base.name = (_name), \
200 .u.div.reg = (_reg), \
201 .u.div.parents = (_parents), \
202 .u.div.nparents = __arraycount(_parents), \
203 .u.div.div = (_div), \
204 .u.div.sel = (_sel), \
205 .u.div.flags = (_flags), \
206 .get_rate = sunxi_ccu_div_get_rate, \
207 .set_rate = sunxi_ccu_div_set_rate, \
208 .set_parent = sunxi_ccu_div_set_parent, \
209 .get_parent = sunxi_ccu_div_get_parent, \
210 }
211
212 struct sunxi_ccu_prediv {
213 bus_size_t reg;
214 const char **parents;
215 u_int nparents;
216 uint32_t prediv;
217 uint32_t prediv_sel;
218 uint32_t div;
219 uint32_t sel;
220 uint32_t flags;
221 #define SUNXI_CCU_PREDIV_POWER_OF_TWO __BIT(0)
222 #define SUNXI_CCU_PREDIV_DIVIDE_BY_TWO __BIT(1)
223 };
224
225 u_int sunxi_ccu_prediv_get_rate(struct sunxi_ccu_softc *,
226 struct sunxi_ccu_clk *);
227 int sunxi_ccu_prediv_set_rate(struct sunxi_ccu_softc *,
228 struct sunxi_ccu_clk *, u_int);
229 int sunxi_ccu_prediv_set_parent(struct sunxi_ccu_softc *,
230 struct sunxi_ccu_clk *,
231 const char *);
232 const char *sunxi_ccu_prediv_get_parent(struct sunxi_ccu_softc *,
233 struct sunxi_ccu_clk *);
234
235 #define SUNXI_CCU_PREDIV(_id, _name, _parents, _reg, _prediv, \
236 _prediv_sel, _div, _sel, _flags) \
237 [_id] = { \
238 .type = SUNXI_CCU_PREDIV, \
239 .base.name = (_name), \
240 .u.prediv.reg = (_reg), \
241 .u.prediv.parents = (_parents), \
242 .u.prediv.nparents = __arraycount(_parents), \
243 .u.prediv.prediv = (_prediv), \
244 .u.prediv.prediv_sel = (_prediv_sel), \
245 .u.prediv.div = (_div), \
246 .u.prediv.sel = (_sel), \
247 .u.prediv.flags = (_flags), \
248 .get_rate = sunxi_ccu_prediv_get_rate, \
249 .set_rate = sunxi_ccu_prediv_set_rate, \
250 .set_parent = sunxi_ccu_prediv_set_parent, \
251 .get_parent = sunxi_ccu_prediv_get_parent, \
252 }
253
254 struct sunxi_ccu_clk {
255 struct clk base;
256 enum sunxi_ccu_clktype type;
257 union {
258 struct sunxi_ccu_gate gate;
259 struct sunxi_ccu_nm nm;
260 struct sunxi_ccu_nkmp nkmp;
261 struct sunxi_ccu_prediv prediv;
262 struct sunxi_ccu_div div;
263 } u;
264
265 int (*enable)(struct sunxi_ccu_softc *,
266 struct sunxi_ccu_clk *, int);
267 u_int (*get_rate)(struct sunxi_ccu_softc *,
268 struct sunxi_ccu_clk *);
269 int (*set_rate)(struct sunxi_ccu_softc *,
270 struct sunxi_ccu_clk *, u_int);
271 const char * (*get_parent)(struct sunxi_ccu_softc *,
272 struct sunxi_ccu_clk *);
273 int (*set_parent)(struct sunxi_ccu_softc *,
274 struct sunxi_ccu_clk *,
275 const char *);
276 };
277
278 struct sunxi_ccu_softc {
279 device_t sc_dev;
280 int sc_phandle;
281 bus_space_tag_t sc_bst;
282 bus_space_handle_t sc_bsh;
283
284 struct clk_domain sc_clkdom;
285
286 struct sunxi_ccu_reset *sc_resets;
287 u_int sc_nresets;
288
289 struct sunxi_ccu_clk *sc_clks;
290 u_int sc_nclks;
291 };
292
293 int sunxi_ccu_attach(struct sunxi_ccu_softc *);
294 struct sunxi_ccu_clk *sunxi_ccu_clock_find(struct sunxi_ccu_softc *,
295 const char *);
296 void sunxi_ccu_print(struct sunxi_ccu_softc *);
297
298 #define CCU_READ(sc, reg) \
299 bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
300 #define CCU_WRITE(sc, reg, val) \
301 bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
302
303 #endif /* _ARM_SUNXI_CCU_H */
304