xref: /openbsd-src/sys/dev/fdt/sxiccmu.c (revision aa997e528a848ca5596493c2a801bdd6fb26ae61)
1 /*	$OpenBSD: sxiccmu.c,v 1.18 2018/02/10 22:31:34 kettenis Exp $	*/
2 /*
3  * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
4  * Copyright (c) 2013 Artturi Alm
5  * Copyright (c) 2016,2017 Mark Kettenis <kettenis@openbsd.org>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/param.h>
21 #include <sys/systm.h>
22 #include <sys/kernel.h>
23 #include <sys/malloc.h>
24 #include <sys/time.h>
25 #include <sys/device.h>
26 
27 #include <machine/bus.h>
28 #include <machine/fdt.h>
29 #include <machine/intr.h>
30 
31 #include <dev/fdt/sunxireg.h>
32 
33 #include <dev/ofw/openfirm.h>
34 #include <dev/ofw/ofw_clock.h>
35 #include <dev/ofw/fdt.h>
36 
37 #ifdef DEBUG_CCMU
38 #define DPRINTF(x)	do { printf x; } while (0)
39 #else
40 #define DPRINTF(x)
41 #endif
42 
43 struct sxiccmu_ccu_bit {
44 	uint16_t reg;
45 	uint8_t bit;
46 	uint8_t parent;
47 };
48 
49 #include "sxiccmu_clocks.h"
50 
51 struct sxiccmu_softc {
52 	struct device		sc_dev;
53 	bus_space_tag_t		sc_iot;
54 	bus_space_handle_t	sc_ioh;
55 	int			sc_node;
56 
57 	struct sxiccmu_ccu_bit	*sc_gates;
58 	int			sc_ngates;
59 	struct clock_device	sc_cd;
60 
61 	struct sxiccmu_ccu_bit	*sc_resets;
62 	int			sc_nresets;
63 	struct reset_device	sc_rd;
64 
65 	uint32_t		(*sc_get_frequency)(struct sxiccmu_softc *,
66 				    uint32_t);
67 	int			(*sc_set_frequency)(struct sxiccmu_softc *,
68 				    uint32_t, uint32_t);
69 };
70 
71 int	sxiccmu_match(struct device *, void *, void *);
72 void	sxiccmu_attach(struct device *, struct device *, void *);
73 
74 struct cfattach	sxiccmu_ca = {
75 	sizeof (struct sxiccmu_softc), sxiccmu_match, sxiccmu_attach
76 };
77 
78 struct cfdriver sxiccmu_cd = {
79 	NULL, "sxiccmu", DV_DULL
80 };
81 
82 void sxiccmu_attach_clock(struct sxiccmu_softc *, int, int);
83 
84 uint32_t sxiccmu_ccu_get_frequency(void *, uint32_t *);
85 int	sxiccmu_ccu_set_frequency(void *, uint32_t *, uint32_t);
86 void	sxiccmu_ccu_enable(void *, uint32_t *, int);
87 void	sxiccmu_ccu_reset(void *, uint32_t *, int);
88 
89 uint32_t sxiccmu_a10_get_frequency(struct sxiccmu_softc *, uint32_t);
90 int	sxiccmu_a10_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t);
91 uint32_t sxiccmu_a23_get_frequency(struct sxiccmu_softc *, uint32_t);
92 int	sxiccmu_a23_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t);
93 uint32_t sxiccmu_a64_get_frequency(struct sxiccmu_softc *, uint32_t);
94 int	sxiccmu_a64_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t);
95 uint32_t sxiccmu_a80_get_frequency(struct sxiccmu_softc *, uint32_t);
96 int	sxiccmu_a80_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t);
97 uint32_t sxiccmu_h3_get_frequency(struct sxiccmu_softc *, uint32_t);
98 int	sxiccmu_h3_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t);
99 uint32_t sxiccmu_h3_r_get_frequency(struct sxiccmu_softc *, uint32_t);
100 uint32_t sxiccmu_r40_get_frequency(struct sxiccmu_softc *, uint32_t);
101 int	sxiccmu_r40_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t);
102 uint32_t sxiccmu_nop_get_frequency(struct sxiccmu_softc *, uint32_t);
103 int	sxiccmu_nop_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t);
104 
105 int
106 sxiccmu_match(struct device *parent, void *match, void *aux)
107 {
108 	struct fdt_attach_args *faa = aux;
109 	int node = faa->fa_node;
110 
111 	if (node == OF_finddevice("/clocks")) {
112 		node = OF_parent(node);
113 
114 		return (OF_is_compatible(node, "allwinner,sun4i-a10") ||
115 		    OF_is_compatible(node, "allwinner,sun5i-a10s") ||
116 		    OF_is_compatible(node, "allwinner,sun5i-r8") ||
117 		    OF_is_compatible(node, "allwinner,sun7i-a20") ||
118 		    OF_is_compatible(node, "allwinner,sun8i-a23") ||
119 		    OF_is_compatible(node, "allwinner,sun8i-a33") ||
120 		    OF_is_compatible(node, "allwinner,sun8i-h3") ||
121 		    OF_is_compatible(node, "allwinner,sun9i-a80") ||
122 		    OF_is_compatible(node, "allwinner,sun50i-a64") ||
123 		    OF_is_compatible(node, "allwinner,sun50i-h5"));
124 	}
125 
126 	return (OF_is_compatible(node, "allwinner,sun4i-a10-ccu") ||
127 	    OF_is_compatible(node, "allwinner,sun7i-a20-ccu") ||
128 	    OF_is_compatible(node, "allwinner,sun8i-a23-ccu") ||
129 	    OF_is_compatible(node, "allwinner,sun8i-a23-prcm") ||
130 	    OF_is_compatible(node, "allwinner,sun8i-a33-ccu") ||
131 	    OF_is_compatible(node, "allwinner,sun8i-h3-ccu") ||
132 	    OF_is_compatible(node, "allwinner,sun8i-h3-r-ccu") ||
133 	    OF_is_compatible(node, "allwinner,sun8i-r40-ccu") ||
134 	    OF_is_compatible(node, "allwinner,sun9i-a80-ccu") ||
135 	    OF_is_compatible(node, "allwinner,sun9i-a80-usb-clks") ||
136 	    OF_is_compatible(node, "allwinner,sun9i-a80-mmc-config-clk") ||
137 	    OF_is_compatible(node, "allwinner,sun50i-a64-ccu") ||
138 	    OF_is_compatible(node, "allwinner,sun50i-a64-r-ccu") ||
139 	    OF_is_compatible(node, "allwinner,sun50i-h5-ccu"));
140 }
141 
142 void
143 sxiccmu_attach(struct device *parent, struct device *self, void *aux)
144 {
145 	struct sxiccmu_softc *sc = (struct sxiccmu_softc *)self;
146 	struct fdt_attach_args *faa = aux;
147 	int node = faa->fa_node;
148 
149 	sc->sc_node = faa->fa_node;
150 	sc->sc_iot = faa->fa_iot;
151 	if (faa->fa_nreg > 0 && bus_space_map(sc->sc_iot,
152 	    faa->fa_reg[0].addr, faa->fa_reg[0].size, 0, &sc->sc_ioh))
153 		panic("%s: bus_space_map failed!", __func__);
154 
155 	printf("\n");
156 
157 	if (OF_is_compatible(node, "allwinner,sun4i-a10-ccu") ||
158 	    OF_is_compatible(node, "allwinner,sun7i-a20-ccu")) {
159 		KASSERT(faa->fa_nreg > 0);
160 		sc->sc_gates = sun4i_a10_gates;
161 		sc->sc_ngates = nitems(sun4i_a10_gates);
162 		sc->sc_resets = sun4i_a10_resets;
163 		sc->sc_nresets = nitems(sun4i_a10_resets);
164 		sc->sc_get_frequency = sxiccmu_a10_get_frequency;
165 		sc->sc_set_frequency = sxiccmu_a10_set_frequency;
166 	} else if (OF_is_compatible(node, "allwinner,sun8i-a23-ccu") ||
167 	    OF_is_compatible(node, "allwinner,sun8i-a33-ccu")) {
168 		KASSERT(faa->fa_nreg > 0);
169 		sc->sc_gates = sun8i_a23_gates;
170 		sc->sc_ngates = nitems(sun8i_a23_gates);
171 		sc->sc_resets = sun8i_a23_resets;
172 		sc->sc_nresets = nitems(sun8i_a23_resets);
173 		sc->sc_get_frequency = sxiccmu_a23_get_frequency;
174 		sc->sc_set_frequency = sxiccmu_a23_set_frequency;
175 	} else if (OF_is_compatible(node, "allwinner,sun8i-h3-ccu") ||
176 	    OF_is_compatible(node, "allwinner,sun50i-h5-ccu")) {
177 		KASSERT(faa->fa_nreg > 0);
178 		sc->sc_gates = sun8i_h3_gates;
179 		sc->sc_ngates = nitems(sun8i_h3_gates);
180 		sc->sc_resets = sun8i_h3_resets;
181 		sc->sc_nresets = nitems(sun8i_h3_resets);
182 		sc->sc_get_frequency = sxiccmu_h3_get_frequency;
183 		sc->sc_set_frequency = sxiccmu_h3_set_frequency;
184 	} else if (OF_is_compatible(node, "allwinner,sun8i-h3-r-ccu") ||
185 	    OF_is_compatible(node, "allwinner,sun50i-a64-r-ccu")) {
186 		KASSERT(faa->fa_nreg > 0);
187 		sc->sc_gates = sun8i_h3_r_gates;
188 		sc->sc_ngates = nitems(sun8i_h3_r_gates);
189 		sc->sc_resets = sun8i_h3_r_resets;
190 		sc->sc_nresets = nitems(sun8i_h3_r_resets);
191 		sc->sc_get_frequency = sxiccmu_h3_r_get_frequency;
192 		sc->sc_set_frequency = sxiccmu_nop_set_frequency;
193 	} else if (OF_is_compatible(node, "allwinner,sun8i-r40-ccu")) {
194 		KASSERT(faa->fa_nreg > 0);
195 		sc->sc_gates = sun8i_r40_gates;
196 		sc->sc_ngates = nitems(sun8i_r40_gates);
197 		sc->sc_resets = sun8i_r40_resets;
198 		sc->sc_nresets = nitems(sun8i_r40_resets);
199 		sc->sc_get_frequency = sxiccmu_r40_get_frequency;
200 		sc->sc_set_frequency = sxiccmu_r40_set_frequency;
201 	} else if (OF_is_compatible(node, "allwinner,sun9i-a80-ccu")) {
202 		KASSERT(faa->fa_nreg > 0);
203 		sc->sc_gates = sun9i_a80_gates;
204 		sc->sc_ngates = nitems(sun9i_a80_gates);
205 		sc->sc_resets = sun9i_a80_resets;
206 		sc->sc_nresets = nitems(sun9i_a80_resets);
207 		sc->sc_get_frequency = sxiccmu_a80_get_frequency;
208 		sc->sc_set_frequency = sxiccmu_a80_set_frequency;
209 	} else if (OF_is_compatible(node, "allwinner,sun9i-a80-usb-clks")) {
210 		KASSERT(faa->fa_nreg > 0);
211 		sc->sc_gates = sun9i_a80_usb_gates;
212 		sc->sc_ngates = nitems(sun9i_a80_usb_gates);
213 		sc->sc_resets = sun9i_a80_usb_resets;
214 		sc->sc_nresets = nitems(sun9i_a80_usb_resets);
215 		sc->sc_get_frequency = sxiccmu_nop_get_frequency;
216 		sc->sc_set_frequency = sxiccmu_nop_set_frequency;
217 	} else if (OF_is_compatible(node, "allwinner,sun9i-a80-mmc-config-clk")) {
218 		KASSERT(faa->fa_nreg > 0);
219 		sc->sc_gates = sun9i_a80_mmc_gates;
220 		sc->sc_ngates = nitems(sun9i_a80_mmc_gates);
221 		sc->sc_resets = sun9i_a80_mmc_resets;
222 		sc->sc_nresets = nitems(sun9i_a80_mmc_resets);
223 		sc->sc_get_frequency = sxiccmu_nop_get_frequency;
224 		sc->sc_set_frequency = sxiccmu_nop_set_frequency;
225 	} else if (OF_is_compatible(node, "allwinner,sun50i-a64-ccu")) {
226 		KASSERT(faa->fa_nreg > 0);
227 		sc->sc_gates = sun50i_a64_gates;
228 		sc->sc_ngates = nitems(sun50i_a64_gates);
229 		sc->sc_resets = sun50i_a64_resets;
230 		sc->sc_nresets = nitems(sun50i_a64_resets);
231 		sc->sc_get_frequency = sxiccmu_a64_get_frequency;
232 		sc->sc_set_frequency = sxiccmu_a64_set_frequency;
233 	} else {
234 		for (node = OF_child(node); node; node = OF_peer(node))
235 			sxiccmu_attach_clock(sc, node, faa->fa_nreg);
236 	}
237 
238 	if (sc->sc_gates) {
239 		sc->sc_cd.cd_node = sc->sc_node;
240 		sc->sc_cd.cd_cookie = sc;
241 		sc->sc_cd.cd_get_frequency = sxiccmu_ccu_get_frequency;
242 		sc->sc_cd.cd_set_frequency = sxiccmu_ccu_set_frequency;
243 		sc->sc_cd.cd_enable = sxiccmu_ccu_enable;
244 		clock_register(&sc->sc_cd);
245 	}
246 
247 	if (sc->sc_resets) {
248 		sc->sc_rd.rd_node = sc->sc_node;
249 		sc->sc_rd.rd_cookie = sc;
250 		sc->sc_rd.rd_reset = sxiccmu_ccu_reset;
251 		reset_register(&sc->sc_rd);
252 	}
253 }
254 
255 /*
256  * Classic device trees for the Allwinner SoCs have basically a clock
257  * node per register of the clock control unit.  Attaching a separate
258  * driver to each of them would be crazy, so we handle them here.
259  */
260 
261 struct sxiccmu_clock {
262 	int sc_node;
263 	bus_space_tag_t sc_iot;
264 	bus_space_handle_t sc_ioh;
265 
266 	struct clock_device sc_cd;
267 	struct reset_device sc_rd;
268 };
269 
270 struct sxiccmu_device {
271 	const char *compat;
272 	uint32_t (*get_frequency)(void *, uint32_t *);
273 	int	(*set_frequency)(void *, uint32_t *, uint32_t);
274 	void	(*enable)(void *, uint32_t *, int);
275 	void	(*reset)(void *, uint32_t *, int);
276 	bus_size_t offset;
277 };
278 
279 uint32_t sxiccmu_gen_get_frequency(void *, uint32_t *);
280 uint32_t sxiccmu_osc_get_frequency(void *, uint32_t *);
281 uint32_t sxiccmu_pll6_get_frequency(void *, uint32_t *);
282 void	sxiccmu_pll6_enable(void *, uint32_t *, int);
283 uint32_t sxiccmu_apb1_get_frequency(void *, uint32_t *);
284 uint32_t sxiccmu_cpus_get_frequency(void *, uint32_t *);
285 uint32_t sxiccmu_apbs_get_frequency(void *, uint32_t *);
286 int	sxiccmu_gmac_set_frequency(void *, uint32_t *, uint32_t);
287 int	sxiccmu_mmc_set_frequency(void *, uint32_t *, uint32_t);
288 void	sxiccmu_mmc_enable(void *, uint32_t *, int);
289 void	sxiccmu_gate_enable(void *, uint32_t *, int);
290 void	sxiccmu_reset(void *, uint32_t *, int);
291 
292 struct sxiccmu_device sxiccmu_devices[] = {
293 	{
294 		.compat = "allwinner,sun4i-a10-osc-clk",
295 		.get_frequency = sxiccmu_osc_get_frequency,
296 	},
297 	{
298 		.compat = "allwinner,sun4i-a10-pll6-clk",
299 		.get_frequency = sxiccmu_pll6_get_frequency,
300 		.enable = sxiccmu_pll6_enable
301 	},
302 	{
303 		.compat = "allwinner,sun4i-a10-apb1-clk",
304 		.get_frequency = sxiccmu_apb1_get_frequency,
305 	},
306 	{
307 		.compat = "allwinner,sun4i-a10-ahb-gates-clk",
308 		.get_frequency = sxiccmu_gen_get_frequency,
309 		.enable = sxiccmu_gate_enable
310 	},
311 	{
312 		.compat = "allwinner,sun4i-a10-apb0-gates-clk",
313 		.get_frequency = sxiccmu_gen_get_frequency,
314 		.enable = sxiccmu_gate_enable
315 	},
316 	{
317 		.compat = "allwinner,sun4i-a10-apb1-gates-clk",
318 		.get_frequency = sxiccmu_gen_get_frequency,
319 		.enable = sxiccmu_gate_enable
320 	},
321 	{
322 		.compat = "allwinner,sun4i-a10-mmc-clk",
323 		.set_frequency = sxiccmu_mmc_set_frequency,
324 		.enable = sxiccmu_mmc_enable
325 	},
326 	{
327 		.compat = "allwinner,sun4i-a10-usb-clk",
328 		.get_frequency = sxiccmu_gen_get_frequency,
329 		.enable = sxiccmu_gate_enable,
330 		.reset = sxiccmu_reset
331 	},
332 	{
333 		.compat = "allwinner,sun5i-a10s-ahb-gates-clk",
334 		.get_frequency = sxiccmu_gen_get_frequency,
335 		.enable = sxiccmu_gate_enable
336 	},
337 	{
338 		.compat = "allwinner,sun5i-a10s-apb0-gates-clk",
339 		.get_frequency = sxiccmu_gen_get_frequency,
340 		.enable = sxiccmu_gate_enable
341 	},
342 	{
343 		.compat = "allwinner,sun5i-a10s-apb1-gates-clk",
344 		.get_frequency = sxiccmu_gen_get_frequency,
345 		.enable = sxiccmu_gate_enable
346 	},
347 	{
348 		.compat = "allwinner,sun5i-a13-ahb-gates-clk",
349 		.get_frequency = sxiccmu_gen_get_frequency,
350 		.enable = sxiccmu_gate_enable
351 	},
352 	{
353 		.compat = "allwinner,sun5i-a13-apb0-gates-clk",
354 		.get_frequency = sxiccmu_gen_get_frequency,
355 		.enable = sxiccmu_gate_enable
356 	},
357 	{
358 		.compat = "allwinner,sun5i-a13-apb1-gates-clk",
359 		.get_frequency = sxiccmu_gen_get_frequency,
360 		.enable = sxiccmu_gate_enable
361 	},
362 	{
363 		.compat = "allwinner,sun5i-a13-usb-clk",
364 		.get_frequency = sxiccmu_gen_get_frequency,
365 		.enable = sxiccmu_gate_enable,
366 		.reset = sxiccmu_reset
367 	},
368 	{
369 		.compat = "allwinner,sun6i-a31-ahb1-reset",
370 		.reset = sxiccmu_reset
371 	},
372 	{
373 		.compat = "allwinner,sun6i-a31-clock-reset",
374 		.reset = sxiccmu_reset,
375 		.offset = 0x00b0
376 	},
377 	{
378 		.compat = "allwinner,sun7i-a20-ahb-gates-clk",
379 		.get_frequency = sxiccmu_gen_get_frequency,
380 		.enable = sxiccmu_gate_enable
381 	},
382 	{
383 		.compat = "allwinner,sun7i-a20-apb0-gates-clk",
384 		.get_frequency = sxiccmu_gen_get_frequency,
385 		.enable = sxiccmu_gate_enable
386 	},
387 	{
388 		.compat = "allwinner,sun7i-a20-apb1-gates-clk",
389 		.get_frequency = sxiccmu_gen_get_frequency,
390 		.enable = sxiccmu_gate_enable
391 	},
392 	{
393 		.compat = "allwinner,sun7i-a20-gmac-clk",
394 		.set_frequency = sxiccmu_gmac_set_frequency
395 	},
396 	{
397 		.compat = "allwinner,sun8i-a23-apb0-clk",
398 		.get_frequency = sxiccmu_apbs_get_frequency,
399 		.offset = 0x000c
400 	},
401 	{
402 		.compat = "allwinner,sun8i-a23-ahb1-gates-clk",
403 		.get_frequency = sxiccmu_gen_get_frequency,
404 		.enable = sxiccmu_gate_enable
405 	},
406 	{
407 		.compat = "allwinner,sun8i-a23-apb0-gates-clk",
408 		.get_frequency = sxiccmu_gen_get_frequency,
409 		.enable = sxiccmu_gate_enable,
410 		.offset = 0x0028
411 	},
412 	{
413 		.compat = "allwinner,sun8i-a23-apb1-gates-clk",
414 		.get_frequency = sxiccmu_gen_get_frequency,
415 		.enable = sxiccmu_gate_enable
416 	},
417 	{
418 		.compat = "allwinner,sun8i-a23-apb2-gates-clk",
419 		.get_frequency = sxiccmu_gen_get_frequency,
420 		.enable = sxiccmu_gate_enable
421 	},
422 	{
423 		.compat = "allwinner,sun8i-a23-usb-clk",
424 		.get_frequency = sxiccmu_gen_get_frequency,
425 		.enable = sxiccmu_gate_enable,
426 		.reset = sxiccmu_reset
427 	},
428 	{
429 		.compat = "allwinner,sun8i-h3-apb0-gates-clk",
430 		.get_frequency = sxiccmu_gen_get_frequency,
431 		.enable = sxiccmu_gate_enable
432 	},
433 	{
434 		.compat = "allwinner,sun9i-a80-apb1-clk",
435 		.get_frequency = sxiccmu_apb1_get_frequency,
436 	},
437 	{
438 		.compat = "allwinner,sun9i-a80-ahb0-gates-clk",
439 		.get_frequency = sxiccmu_gen_get_frequency,
440 		.enable = sxiccmu_gate_enable
441 	},
442 	{
443 		.compat = "allwinner,sun9i-a80-ahb1-gates-clk",
444 		.get_frequency = sxiccmu_gen_get_frequency,
445 		.enable = sxiccmu_gate_enable
446 	},
447 	{
448 		.compat = "allwinner,sun9i-a80-ahb2-gates-clk",
449 		.get_frequency = sxiccmu_gen_get_frequency,
450 		.enable = sxiccmu_gate_enable
451 	},
452 	{
453 		.compat = "allwinner,sun9i-a80-apb0-gates-clk",
454 		.get_frequency = sxiccmu_gen_get_frequency,
455 		.enable = sxiccmu_gate_enable
456 	},
457 	{
458 		.compat = "allwinner,sun9i-a80-apb1-gates-clk",
459 		.get_frequency = sxiccmu_gen_get_frequency,
460 		.enable = sxiccmu_gate_enable
461 	},
462 	{
463 		.compat = "allwinner,sun9i-a80-apbs-gates-clk",
464 		.get_frequency = sxiccmu_gen_get_frequency,
465 		.enable = sxiccmu_gate_enable
466 	},
467 	{
468 		.compat = "allwinner,sun9i-a80-cpus-clk",
469 		.get_frequency = sxiccmu_cpus_get_frequency
470 	},
471 	{
472 		.compat = "allwinner,sun9i-a80-mmc-clk",
473 		.set_frequency = sxiccmu_mmc_set_frequency,
474 		.enable = sxiccmu_mmc_enable
475 	},
476 	{
477 		.compat = "allwinner,sun9i-a80-usb-mod-clk",
478 		.get_frequency = sxiccmu_gen_get_frequency,
479 		.enable = sxiccmu_gate_enable,
480 		.reset = sxiccmu_reset
481 	},
482 	{
483 		.compat = "allwinner,sun9i-a80-usb-phy-clk",
484 		.get_frequency = sxiccmu_gen_get_frequency,
485 		.enable = sxiccmu_gate_enable,
486 		.reset = sxiccmu_reset
487 	},
488 };
489 
490 void
491 sxiccmu_attach_clock(struct sxiccmu_softc *sc, int node, int nreg)
492 {
493 	struct sxiccmu_clock *clock;
494 	uint32_t reg[2];
495 	int i, error = ENODEV;
496 
497 	for (i = 0; i < nitems(sxiccmu_devices); i++)
498 		if (OF_is_compatible(node, sxiccmu_devices[i].compat))
499 			break;
500 	if (i == nitems(sxiccmu_devices))
501 		return;
502 
503 	clock = malloc(sizeof(*clock), M_DEVBUF, M_WAITOK);
504 	clock->sc_node = node;
505 
506 	clock->sc_iot = sc->sc_iot;
507 	if (OF_getpropintarray(node, "reg", reg, sizeof(reg)) == sizeof(reg)) {
508 		error = bus_space_map(clock->sc_iot, reg[0], reg[1], 0,
509 		    &clock->sc_ioh);
510 	} else if (nreg > 0) {
511 		error = bus_space_subregion(clock->sc_iot, sc->sc_ioh,
512 		    sxiccmu_devices[i].offset, 4, &clock->sc_ioh);
513 	}
514 	if (error) {
515 		printf("%s: can't map registers", sc->sc_dev.dv_xname);
516 		free(clock, M_DEVBUF, sizeof(*clock));
517 		return;
518 	}
519 
520 	clock->sc_cd.cd_node = node;
521 	clock->sc_cd.cd_cookie = clock;
522 	clock->sc_cd.cd_get_frequency = sxiccmu_devices[i].get_frequency;
523 	clock->sc_cd.cd_set_frequency = sxiccmu_devices[i].set_frequency;
524 	clock->sc_cd.cd_enable = sxiccmu_devices[i].enable;
525 	clock_register(&clock->sc_cd);
526 
527 	if (sxiccmu_devices[i].reset) {
528 		clock->sc_rd.rd_node = node;
529 		clock->sc_rd.rd_cookie = clock;
530 		clock->sc_rd.rd_reset = sxiccmu_devices[i].reset;
531 		reset_register(&clock->sc_rd);
532 	}
533 }
534 
535 /*
536  * A "generic" function that simply gets the clock frequency from the
537  * parent clock.  Useful for clock gating devices that don't scale
538  * their clocks.
539  */
540 uint32_t
541 sxiccmu_gen_get_frequency(void *cookie, uint32_t *cells)
542 {
543 	struct sxiccmu_clock *sc = cookie;
544 
545 	return clock_get_frequency(sc->sc_node, NULL);
546 }
547 
548 uint32_t
549 sxiccmu_osc_get_frequency(void *cookie, uint32_t *cells)
550 {
551 	struct sxiccmu_clock *sc = cookie;
552 
553 	return OF_getpropint(sc->sc_node, "clock-frequency", 24000000);
554 }
555 
556 #define CCU_PLL6_ENABLE			(1U << 31)
557 #define CCU_PLL6_BYPASS_EN		(1U << 30)
558 #define CCU_PLL6_SATA_CLK_EN		(1U << 14)
559 #define CCU_PLL6_FACTOR_N(x)		(((x) >> 8) & 0x1f)
560 #define CCU_PLL6_FACTOR_N_MASK		(0x1f << 8)
561 #define CCU_PLL6_FACTOR_N_SHIFT		8
562 #define CCU_PLL6_FACTOR_K(x)		(((x) >> 4) & 0x3)
563 #define CCU_PLL6_FACTOR_K_MASK		(0x3 << 4)
564 #define CCU_PLL6_FACTOR_K_SHIFT		4
565 #define CCU_PLL6_FACTOR_M(x)		(((x) >> 0) & 0x3)
566 #define CCU_PLL6_FACTOR_M_MASK		(0x3 << 0)
567 #define CCU_PLL6_FACTOR_M_SHIFT		0
568 
569 uint32_t
570 sxiccmu_pll6_get_frequency(void *cookie, uint32_t *cells)
571 {
572 	struct sxiccmu_clock *sc = cookie;
573 	uint32_t reg, k, m, n, freq;
574 	uint32_t idx = cells[0];
575 
576 	/* XXX Assume bypass is disabled. */
577 	reg = SXIREAD4(sc, 0);
578 	k = CCU_PLL6_FACTOR_K(reg) + 1;
579 	m = CCU_PLL6_FACTOR_M(reg) + 1;
580 	n = CCU_PLL6_FACTOR_N(reg);
581 
582 	freq = clock_get_frequency_idx(sc->sc_node, 0);
583 	switch (idx) {
584 	case 0:
585 		return (freq * n * k) / m / 6;		/* pll6_sata */
586 	case 1:
587 		return (freq * n * k) / 2;		/* pll6_other */
588 	case 2:
589 		return (freq * n * k);			/* pll6 */
590 	case 3:
591 		return (freq * n * k) / 4;		/* pll6_div_4 */
592 	}
593 
594 	return 0;
595 }
596 
597 void
598 sxiccmu_pll6_enable(void *cookie, uint32_t *cells, int on)
599 {
600 	struct sxiccmu_clock *sc = cookie;
601 	uint32_t idx = cells[0];
602 	uint32_t reg;
603 
604 	/*
605 	 * Since this clock has several outputs, we never turn it off.
606 	 */
607 
608 	reg = SXIREAD4(sc, 0);
609 	switch (idx) {
610 	case 0:			/* pll6_sata */
611 		if (on)
612 			reg |= CCU_PLL6_SATA_CLK_EN;
613 		else
614 			reg &= ~CCU_PLL6_SATA_CLK_EN;
615 		/* FALLTHROUGH */
616 	case 1:			/* pll6_other */
617 	case 2:			/* pll6 */
618 	case 3:			/* pll6_div_4 */
619 		if (on)
620 			reg |= CCU_PLL6_ENABLE;
621 	}
622 	SXIWRITE4(sc, 0, reg);
623 }
624 
625 #define CCU_APB1_CLK_RAT_N(x)		(((x) >> 16) & 0x3)
626 #define CCU_APB1_CLK_RAT_M(x)		(((x) >> 0) & 0x1f)
627 #define CCU_APB1_CLK_SRC_SEL(x)		(((x) >> 24) & 0x3)
628 
629 uint32_t
630 sxiccmu_apb1_get_frequency(void *cookie, uint32_t *cells)
631 {
632 	struct sxiccmu_clock *sc = cookie;
633 	uint32_t reg, m, n, freq;
634 	int idx;
635 
636 	reg = SXIREAD4(sc, 0);
637 	m = CCU_APB1_CLK_RAT_M(reg);
638 	n = CCU_APB1_CLK_RAT_N(reg);
639 	idx = CCU_APB1_CLK_SRC_SEL(reg);
640 
641 	freq = clock_get_frequency_idx(sc->sc_node, idx);
642 	return freq / (1 << n) / (m + 1);
643 }
644 
645 #define CCU_CPUS_CLK_SRC_SEL(x)		(((x) >> 16) & 0x3)
646 #define CCU_CPUS_POST_DIV(x)		(((x) >> 8) & 0x1f)
647 #define CCU_CPUS_CLK_RATIO(x)		(((x) >> 0) & 0x3)
648 
649 uint32_t
650 sxiccmu_cpus_get_frequency(void *cookie, uint32_t *cells)
651 {
652 	struct sxiccmu_clock *sc = cookie;
653 	uint32_t reg, post_div, clk_ratio, freq;
654 	int idx;
655 
656 	reg = SXIREAD4(sc, 0);
657 	idx = CCU_CPUS_CLK_SRC_SEL(reg);
658 	post_div = (idx == 2 ? CCU_CPUS_POST_DIV(reg): 0);
659 	clk_ratio = CCU_CPUS_CLK_RATIO(reg);
660 
661 	freq = clock_get_frequency_idx(sc->sc_node, idx);
662 	return freq / (clk_ratio + 1) / (post_div + 1);
663 }
664 
665 #define CCU_APBS_CLK_RATIO(x)		(((x) >> 0) & 0x3)
666 
667 uint32_t
668 sxiccmu_apbs_get_frequency(void *cookie, uint32_t *cells)
669 {
670 	struct sxiccmu_clock *sc = cookie;
671 	uint32_t reg, freq;
672 
673 	reg = SXIREAD4(sc, 0);
674 	freq = clock_get_frequency(sc->sc_node, NULL);
675 	return freq / (CCU_APBS_CLK_RATIO(reg) + 1);
676 }
677 
678 #define	CCU_GMAC_CLK_PIT		(1 << 2)
679 #define	CCU_GMAC_CLK_TCS		(3 << 0)
680 #define	CCU_GMAC_CLK_TCS_MII		0
681 #define	CCU_GMAC_CLK_TCS_EXT_125	1
682 #define	CCU_GMAC_CLK_TCS_INT_RGMII	2
683 
684 int
685 sxiccmu_gmac_set_frequency(void *cookie, uint32_t *cells, uint32_t freq)
686 {
687 	struct sxiccmu_clock *sc = cookie;
688 
689 	switch (freq) {
690 	case 25000000:		/* MMI, 25 MHz */
691 		SXICMS4(sc, 0, CCU_GMAC_CLK_PIT|CCU_GMAC_CLK_TCS,
692 		    CCU_GMAC_CLK_TCS_MII);
693 		break;
694 	case 125000000:		/* RGMII, 125 MHz */
695 		SXICMS4(sc, 0, CCU_GMAC_CLK_PIT|CCU_GMAC_CLK_TCS,
696 		    CCU_GMAC_CLK_PIT|CCU_GMAC_CLK_TCS_INT_RGMII);
697 		break;
698 	default:
699 		return -1;
700 	}
701 
702 	return 0;
703 }
704 
705 #define CCU_SDx_SCLK_GATING		(1U << 31)
706 #define CCU_SDx_CLK_SRC_SEL_OSC24M	(0 << 24)
707 #define CCU_SDx_CLK_SRC_SEL_PLL6	(1 << 24)
708 #define CCU_SDx_CLK_SRC_SEL_PLL5	(2 << 24)
709 #define CCU_SDx_CLK_SRC_SEL_MASK	(3 << 24)
710 #define CCU_SDx_CLK_DIV_RATIO_N_MASK	(3 << 16)
711 #define CCU_SDx_CLK_DIV_RATIO_N_SHIFT	16
712 #define CCU_SDx_CLK_DIV_RATIO_M_MASK	(7 << 0)
713 #define CCU_SDx_CLK_DIV_RATIO_M_SHIFT	0
714 
715 int
716 sxiccmu_mmc_do_set_frequency(struct sxiccmu_clock *sc, uint32_t freq,
717     uint32_t parent_freq)
718 {
719 	uint32_t reg, m, n;
720 	uint32_t clk_src;
721 
722 	switch (freq) {
723 	case 400000:
724 		n = 2, m = 15;
725 		clk_src = CCU_SDx_CLK_SRC_SEL_OSC24M;
726 		break;
727 	case 25000000:
728 	case 26000000:
729 	case 50000000:
730 	case 52000000:
731 		n = 0, m = 0;
732 		clk_src = CCU_SDx_CLK_SRC_SEL_PLL6;
733 		while ((parent_freq / (1 << n) / 16) > freq)
734 			n++;
735 		while ((parent_freq / (1 << n) / (m + 1)) > freq)
736 			m++;
737 		break;
738 	default:
739 		return -1;
740 	}
741 
742 	reg = SXIREAD4(sc, 0);
743 	reg &= ~CCU_SDx_CLK_SRC_SEL_MASK;
744 	reg |= clk_src;
745 	reg &= ~CCU_SDx_CLK_DIV_RATIO_N_MASK;
746 	reg |= n << CCU_SDx_CLK_DIV_RATIO_N_SHIFT;
747 	reg &= ~CCU_SDx_CLK_DIV_RATIO_M_MASK;
748 	reg |= m << CCU_SDx_CLK_DIV_RATIO_M_SHIFT;
749 	SXIWRITE4(sc, 0, reg);
750 
751 	return 0;
752 }
753 
754 int
755 sxiccmu_mmc_set_frequency(void *cookie, uint32_t *cells, uint32_t freq)
756 {
757 	struct sxiccmu_clock *sc = cookie;
758 	uint32_t parent_freq;
759 
760 	if (cells[0] != 0)
761 		return -1;
762 
763 	parent_freq = clock_get_frequency_idx(sc->sc_node, 1);
764 	return sxiccmu_mmc_do_set_frequency(sc, freq, parent_freq);
765 }
766 
767 void
768 sxiccmu_mmc_enable(void *cookie, uint32_t *cells, int on)
769 {
770 	struct sxiccmu_clock *sc = cookie;
771 
772 	if (cells[0] != 0)
773 		return;
774 
775 	if (on)
776 		SXISET4(sc, 0, CCU_SDx_SCLK_GATING);
777 	else
778 		SXICLR4(sc, 0, CCU_SDx_SCLK_GATING);
779 }
780 
781 void
782 sxiccmu_gate_enable(void *cookie, uint32_t *cells, int on)
783 {
784 	struct sxiccmu_clock *sc = cookie;
785 	int reg = cells[0] / 32;
786 	int bit = cells[0] % 32;
787 
788 	if (on) {
789 		clock_enable(sc->sc_node, NULL);
790 		SXISET4(sc, reg * 4, (1U << bit));
791 	} else {
792 		SXICLR4(sc, reg * 4, (1U << bit));
793 		clock_disable(sc->sc_node, NULL);
794 	}
795 }
796 
797 void
798 sxiccmu_reset(void *cookie, uint32_t *cells, int assert)
799 {
800 	struct sxiccmu_clock *sc = cookie;
801 	int reg = cells[0] / 32;
802 	int bit = cells[0] % 32;
803 
804 	if (assert)
805 		SXICLR4(sc, reg * 4, (1U << bit));
806 	else
807 		SXISET4(sc, reg * 4, (1U << bit));
808 }
809 
810 /*
811  * Newer device trees, such as those for the Allwinner H3/A64 have
812  * most of the clock nodes replaced with a single clock control unit
813  * node.
814  */
815 
816 uint32_t
817 sxiccmu_ccu_get_frequency(void *cookie, uint32_t *cells)
818 {
819 	struct sxiccmu_softc *sc = cookie;
820 	uint32_t idx = cells[0];
821 	uint32_t parent;
822 
823 	if (idx < sc->sc_ngates && sc->sc_gates[idx].parent) {
824 		parent = sc->sc_gates[idx].parent;
825 		return sxiccmu_ccu_get_frequency(sc, &parent);
826 	}
827 
828 	return sc->sc_get_frequency(sc, idx);
829 }
830 
831 /* Allwinner A10/A20 */
832 #define A10_PLL1_CFG_REG		0x0000
833 #define A10_PLL1_OUT_EXT_DIVP(x)	(((x) >> 16) & 0x3)
834 #define A10_PLL1_FACTOR_N(x)		(((x) >> 8) & 0x1f)
835 #define A10_PLL1_FACTOR_K(x)		(((x) >> 4) & 0x3)
836 #define A10_PLL1_FACTOR_M(x)		(((x) >> 0) & 0x3)
837 #define A10_CPU_AHB_APB0_CFG_REG	0x0054
838 #define A10_CPU_CLK_SRC_SEL		(0x3 << 16)
839 #define A10_CPU_CLK_SRC_SEL_LOSC	(0x0 << 16)
840 #define A10_CPU_CLK_SRC_SEL_OSC24M	(0x1 << 16)
841 #define A10_CPU_CLK_SRC_SEL_PLL1	(0x2 << 16)
842 #define A10_CPU_CLK_SRC_SEL_200MHZ	(0x3 << 16)
843 
844 uint32_t
845 sxiccmu_a10_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
846 {
847 	uint32_t parent;
848 	uint32_t reg, k, m, n, p;
849 
850 	switch (idx) {
851 	case A10_CLK_LOSC:
852 		return clock_get_frequency(sc->sc_node, "losc");
853 	case A10_CLK_HOSC:
854 		return clock_get_frequency(sc->sc_node, "hosc");
855 	case A10_CLK_PLL_CORE:
856 		reg = SXIREAD4(sc, A10_PLL1_CFG_REG);
857 		k = A10_PLL1_FACTOR_K(reg) + 1;
858 		m = A10_PLL1_FACTOR_M(reg) + 1;
859 		n = A10_PLL1_FACTOR_N(reg);
860 		p = 1 << A10_PLL1_OUT_EXT_DIVP(reg);
861 		return (24000000 * n * k) / (m * p);
862 	case A10_CLK_PLL_PERIPH_BASE:
863 		/* Not hardcoded, but recommended. */
864 		return 600000000;
865 	case A10_CLK_PLL_PERIPH:
866 		return sxiccmu_a10_get_frequency(sc, A10_CLK_PLL_PERIPH_BASE) * 2;
867 	case A10_CLK_CPU:
868 		reg = SXIREAD4(sc, A10_CPU_AHB_APB0_CFG_REG);
869 		switch (reg & A10_CPU_CLK_SRC_SEL) {
870 		case A10_CPU_CLK_SRC_SEL_LOSC:
871 			parent = A10_CLK_LOSC;
872 			break;
873 		case A10_CPU_CLK_SRC_SEL_OSC24M:
874 			parent = A10_CLK_HOSC;
875 			break;
876 		case A10_CPU_CLK_SRC_SEL_PLL1:
877 			parent = A10_CLK_PLL_CORE;
878 			break;
879 		case A10_CPU_CLK_SRC_SEL_200MHZ:
880 			return 200000000;
881 		}
882 		return sxiccmu_ccu_get_frequency(sc, &parent);
883 	case A10_CLK_APB1:
884 		/* XXX Controlled by a MUX. */
885 		return 24000000;
886 	}
887 
888 	printf("%s: 0x%08x\n", __func__, idx);
889 	return 0;
890 }
891 
892 /* Allwinner H3/A64 */
893 #define CCU_AHB1_APB1_CFG_REG		0x0054
894 #define CCU_AHB1_CLK_SRC_SEL		(3 << 12)
895 #define CCU_AHB1_CLK_SRC_SEL_LOSC	(0 << 12)
896 #define CCU_AHB1_CLK_SRC_SEL_OSC24M	(1 << 12)
897 #define CCU_AHB1_CLK_SRC_SEL_AXI	(2 << 12)
898 #define CCU_AHB1_CLK_SRC_SEL_PERIPH0	(3 << 12)
899 #define CCU_AHB1_PRE_DIV(x)		((((x) >> 6) & 3) + 1)
900 #define CCU_AHB1_CLK_DIV_RATIO(x)	(1 << (((x) >> 4) & 3))
901 #define CCU_AHB2_CFG_REG		0x005c
902 #define CCU_AHB2_CLK_CFG		(3 << 0)
903 
904 uint32_t
905 sxiccmu_a23_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
906 {
907 	uint32_t parent;
908 	uint32_t reg, div;
909 
910 	switch (idx) {
911 	case A23_CLK_LOSC:
912 		return clock_get_frequency(sc->sc_node, "losc");
913 	case A23_CLK_HOSC:
914 		return clock_get_frequency(sc->sc_node, "hosc");
915 	case A23_CLK_PLL_PERIPH:
916 		/* Not hardcoded, but recommended. */
917 		return 600000000;
918 	case A23_CLK_APB2:
919 		/* XXX Controlled by a MUX. */
920 		return 24000000;
921 	case A23_CLK_AHB1:
922 		reg = SXIREAD4(sc, CCU_AHB1_APB1_CFG_REG);
923 		div = CCU_AHB1_CLK_DIV_RATIO(reg);
924 		switch (reg & CCU_AHB1_CLK_SRC_SEL) {
925 		case CCU_AHB1_CLK_SRC_SEL_LOSC:
926 			parent = A23_CLK_LOSC;
927 			break;
928 		case CCU_AHB1_CLK_SRC_SEL_OSC24M:
929 			parent = A23_CLK_HOSC;
930 			break;
931 		case CCU_AHB1_CLK_SRC_SEL_AXI:
932 			parent = A23_CLK_AXI;
933 			break;
934 		case CCU_AHB1_CLK_SRC_SEL_PERIPH0:
935 			parent = A23_CLK_PLL_PERIPH;
936 			div *= CCU_AHB1_PRE_DIV(reg);
937 			break;
938 		default:
939 			return 0;
940 		}
941 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
942 	}
943 
944 	printf("%s: 0x%08x\n", __func__, idx);
945 	return 0;
946 }
947 
948 uint32_t
949 sxiccmu_a64_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
950 {
951 	uint32_t parent;
952 	uint32_t reg, div;
953 
954 	switch (idx) {
955 	case A64_CLK_LOSC:
956 		return clock_get_frequency(sc->sc_node, "losc");
957 	case A64_CLK_HOSC:
958 		return clock_get_frequency(sc->sc_node, "hosc");
959 	case A64_CLK_PLL_PERIPH0:
960 		/* Not hardcoded, but recommended. */
961 		return 600000000;
962 	case A64_CLK_PLL_PERIPH0_2X:
963 		return sxiccmu_a64_get_frequency(sc, A64_CLK_PLL_PERIPH0) * 2;
964 	case A64_CLK_APB2:
965 		/* XXX Controlled by a MUX. */
966 		return 24000000;
967 	case A64_CLK_AHB1:
968 		reg = SXIREAD4(sc, CCU_AHB1_APB1_CFG_REG);
969 		div = CCU_AHB1_CLK_DIV_RATIO(reg);
970 		switch (reg & CCU_AHB1_CLK_SRC_SEL) {
971 		case CCU_AHB1_CLK_SRC_SEL_LOSC:
972 			parent = A64_CLK_LOSC;
973 			break;
974 		case CCU_AHB1_CLK_SRC_SEL_OSC24M:
975 			parent = A64_CLK_HOSC;
976 			break;
977 		case CCU_AHB1_CLK_SRC_SEL_AXI:
978 			parent = A64_CLK_AXI;
979 			break;
980 		case CCU_AHB1_CLK_SRC_SEL_PERIPH0:
981 			parent = A64_CLK_PLL_PERIPH0;
982 			div *= CCU_AHB1_PRE_DIV(reg);
983 			break;
984 		default:
985 			return 0;
986 		}
987 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
988 	case A64_CLK_AHB2:
989 		reg = SXIREAD4(sc, CCU_AHB2_CFG_REG);
990 		switch (reg & CCU_AHB2_CLK_CFG) {
991 		case 0:
992 			parent = A64_CLK_AHB1;
993 			div = 1;
994 			break;
995 		case 1:
996 			parent = A64_CLK_PLL_PERIPH0;
997 			div = 2;
998 			break;
999 		default:
1000 			return 0;
1001 		}
1002 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
1003 	}
1004 
1005 	printf("%s: 0x%08x\n", __func__, idx);
1006 	return 0;
1007 }
1008 
1009 uint32_t
1010 sxiccmu_a80_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
1011 {
1012 	switch (idx) {
1013 	case A80_CLK_PLL_PERIPH0:
1014 		/* Not hardcoded, but recommended. */
1015 		return 960000000;
1016 	case A80_CLK_APB1:
1017 		/* XXX Controlled by a MUX. */
1018 		return 24000000;
1019 	}
1020 
1021 	printf("%s: 0x%08x\n", __func__, idx);
1022 	return 0;
1023 }
1024 
1025 /* Allwinner H3/H5 */
1026 #define H3_PLL_CPUX_CTRL_REG		0x0000
1027 #define H3_PLL_CPUX_OUT_EXT_DIVP(x)	(((x) >> 16) & 0x3)
1028 #define H3_PLL_CPUX_FACTOR_N(x)		(((x) >> 8) & 0x1f)
1029 #define H3_PLL_CPUX_FACTOR_K(x)		(((x) >> 4) & 0x3)
1030 #define H3_PLL_CPUX_FACTOR_M(x)		(((x) >> 0) & 0x3)
1031 #define H3_CPUX_AXI_CFG_REG		0x0050
1032 #define H3_CPUX_CLK_SRC_SEL		(0x3 << 16)
1033 #define H3_CPUX_CLK_SRC_SEL_LOSC	(0x0 << 16)
1034 #define H3_CPUX_CLK_SRC_SEL_OSC24M	(0x1 << 16)
1035 #define H3_CPUX_CLK_SRC_SEL_PLL_CPUX	(0x2 << 16)
1036 
1037 uint32_t
1038 sxiccmu_h3_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
1039 {
1040 	uint32_t parent;
1041 	uint32_t reg, div;
1042 	uint32_t k, m, n, p;
1043 
1044 	switch (idx) {
1045 	case H3_CLK_LOSC:
1046 		return clock_get_frequency(sc->sc_node, "losc");
1047 	case H3_CLK_HOSC:
1048 		return clock_get_frequency(sc->sc_node, "hosc");
1049 	case H3_CLK_PLL_CPUX:
1050 		reg = SXIREAD4(sc, H3_PLL_CPUX_CTRL_REG);
1051 		k = H3_PLL_CPUX_FACTOR_K(reg) + 1;
1052 		m = H3_PLL_CPUX_FACTOR_M(reg) + 1;
1053 		n = H3_PLL_CPUX_FACTOR_N(reg) + 1;
1054 		p = 1 << H3_PLL_CPUX_OUT_EXT_DIVP(reg);
1055 		return (24000000 * n * k) / (m * p);
1056 	case H3_CLK_PLL_PERIPH0:
1057 		/* Not hardcoded, but recommended. */
1058 		return 600000000;
1059 	case H3_CLK_CPUX:
1060 		reg = SXIREAD4(sc, H3_CPUX_AXI_CFG_REG);
1061 		switch (reg & H3_CPUX_CLK_SRC_SEL) {
1062 		case H3_CPUX_CLK_SRC_SEL_LOSC:
1063 			parent = H3_CLK_LOSC;
1064 			break;
1065 		case H3_CPUX_CLK_SRC_SEL_OSC24M:
1066 			parent = H3_CLK_HOSC;
1067 			break;
1068 		case H3_CPUX_CLK_SRC_SEL_PLL_CPUX:
1069 			parent = H3_CLK_PLL_CPUX;
1070 			break;
1071 		default:
1072 			return 0;
1073 		}
1074 		return sxiccmu_ccu_get_frequency(sc, &parent);
1075 	case H3_CLK_APB2:
1076 		/* XXX Controlled by a MUX. */
1077 		return 24000000;
1078 	case H3_CLK_AHB1:
1079 		reg = SXIREAD4(sc, CCU_AHB1_APB1_CFG_REG);
1080 		div = CCU_AHB1_CLK_DIV_RATIO(reg);
1081 		switch (reg & CCU_AHB1_CLK_SRC_SEL) {
1082 		case CCU_AHB1_CLK_SRC_SEL_LOSC:
1083 			parent = H3_CLK_LOSC;
1084 			break;
1085 		case CCU_AHB1_CLK_SRC_SEL_OSC24M:
1086 			parent = H3_CLK_HOSC;
1087 			break;
1088 		case CCU_AHB1_CLK_SRC_SEL_AXI:
1089 			parent = H3_CLK_AXI;
1090 			break;
1091 		case CCU_AHB1_CLK_SRC_SEL_PERIPH0:
1092 			parent = H3_CLK_PLL_PERIPH0;
1093 			div *= CCU_AHB1_PRE_DIV(reg);
1094 			break;
1095 		default:
1096 			return 0;
1097 		}
1098 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
1099 	case H3_CLK_AHB2:
1100 		reg = SXIREAD4(sc, CCU_AHB2_CFG_REG);
1101 		switch (reg & CCU_AHB2_CLK_CFG) {
1102 		case 0:
1103 			parent = H3_CLK_AHB1;
1104 			div = 1;
1105 			break;
1106 		case 1:
1107 			parent = H3_CLK_PLL_PERIPH0;
1108 			div = 2;
1109 			break;
1110 		default:
1111 			return 0;
1112 		}
1113 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
1114 	}
1115 
1116 	printf("%s: 0x%08x\n", __func__, idx);
1117 	return 0;
1118 }
1119 
1120 #define H3_AHB0_CLK_REG			0x0000
1121 #define H3_AHB0_CLK_SRC_SEL		(0x3 << 16)
1122 #define H3_AHB0_CLK_SRC_SEL_OSC32K	(0x0 << 16)
1123 #define H3_AHB0_CLK_SRC_SEL_OSC24M	(0x1 << 16)
1124 #define H3_AHB0_CLK_SRC_SEL_PLL_PERIPH0	(0x2 << 16)
1125 #define H3_AHB0_CLK_SRC_SEL_IOSC	(0x3 << 16)
1126 #define H3_AHB0_CLK_PRE_DIV(x)		((((x) >> 8) & 0x1f) + 1)
1127 #define H3_AHB0_CLK_RATIO(x)		(1 << (((x) >> 4) & 3))
1128 #define H3_APB0_CFG_REG			0x000c
1129 #define H3_APB0_CLK_RATIO(x)		(1 << ((x) & 1))
1130 
1131 uint32_t
1132 sxiccmu_h3_r_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
1133 {
1134 	uint32_t parent;
1135 	uint32_t reg, div;
1136 	uint32_t freq;
1137 
1138 	switch (idx) {
1139 	case H3_R_CLK_AHB0:
1140 		reg = SXIREAD4(sc, H3_AHB0_CLK_REG);
1141 		switch (reg & H3_AHB0_CLK_SRC_SEL) {
1142 		case H3_AHB0_CLK_SRC_SEL_OSC32K:
1143 			freq = clock_get_frequency(sc->sc_node, "losc");
1144 			break;
1145 		case H3_AHB0_CLK_SRC_SEL_OSC24M:
1146 			freq = clock_get_frequency(sc->sc_node, "hosc");
1147 			break;
1148 		case H3_AHB0_CLK_SRC_SEL_PLL_PERIPH0:
1149 			freq = clock_get_frequency(sc->sc_node, "pll-periph");
1150 			break;
1151 		case H3_AHB0_CLK_SRC_SEL_IOSC:
1152 			freq = clock_get_frequency(sc->sc_node, "iosc");
1153 			break;
1154 		}
1155 		div = H3_AHB0_CLK_PRE_DIV(reg) * H3_AHB0_CLK_RATIO(reg);
1156 		return freq / div;
1157 	case H3_R_CLK_APB0:
1158 		reg = SXIREAD4(sc, H3_APB0_CFG_REG);
1159 		div = H3_APB0_CLK_RATIO(reg);
1160 		parent = H3_R_CLK_AHB0;
1161 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
1162 	}
1163 
1164 	printf("%s: 0x%08x\n", __func__, idx);
1165 	return 0;
1166 }
1167 
1168 uint32_t
1169 sxiccmu_r40_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
1170 {
1171 	switch (idx) {
1172 	case R40_CLK_PLL_PERIPH0:
1173 		/* Not hardcoded, but recommended. */
1174 		return 600000000;
1175 	case R40_CLK_PLL_PERIPH0_2X:
1176 		return sxiccmu_r40_get_frequency(sc, A64_CLK_PLL_PERIPH0) * 2;
1177 	case R40_CLK_APB2:
1178 		/* XXX Controlled by a MUX. */
1179 		return 24000000;
1180 	}
1181 
1182 	printf("%s: 0x%08x\n", __func__, idx);
1183 	return 0;
1184 }
1185 
1186 uint32_t
1187 sxiccmu_nop_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
1188 {
1189 	printf("%s: 0x%08x\n", __func__, idx);
1190 	return 0;
1191 }
1192 
1193 int
1194 sxiccmu_ccu_set_frequency(void *cookie, uint32_t *cells, uint32_t freq)
1195 {
1196 	struct sxiccmu_softc *sc = cookie;
1197 	uint32_t idx = cells[0];
1198 
1199 	return sc->sc_set_frequency(sc, idx, freq);
1200 }
1201 
1202 int
1203 sxiccmu_a10_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1204 {
1205 	struct sxiccmu_clock clock;
1206 	uint32_t parent, parent_freq;
1207 
1208 	switch (idx) {
1209 	case A10_CLK_MMC0:
1210 	case A10_CLK_MMC1:
1211 	case A10_CLK_MMC2:
1212 	case A10_CLK_MMC3:
1213 		clock.sc_iot = sc->sc_iot;
1214 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
1215 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
1216 		parent = A10_CLK_PLL_PERIPH;
1217 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
1218 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
1219 	}
1220 
1221 	printf("%s: 0x%08x\n", __func__, idx);
1222 	return -1;
1223 }
1224 
1225 int
1226 sxiccmu_a23_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1227 {
1228 	struct sxiccmu_clock clock;
1229 	uint32_t parent, parent_freq;
1230 
1231 	switch (idx) {
1232 	case A23_CLK_MMC0:
1233 	case A23_CLK_MMC1:
1234 	case A23_CLK_MMC2:
1235 		clock.sc_iot = sc->sc_iot;
1236 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
1237 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
1238 		parent = A23_CLK_PLL_PERIPH;
1239 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
1240 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
1241 	}
1242 
1243 	printf("%s: 0x%08x\n", __func__, idx);
1244 	return -1;
1245 }
1246 
1247 int
1248 sxiccmu_a64_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1249 {
1250 	struct sxiccmu_clock clock;
1251 	uint32_t parent, parent_freq;
1252 
1253 	switch (idx) {
1254 	case A64_CLK_MMC0:
1255 	case A64_CLK_MMC1:
1256 	case A64_CLK_MMC2:
1257 		clock.sc_iot = sc->sc_iot;
1258 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
1259 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
1260 		parent = A64_CLK_PLL_PERIPH0_2X;
1261 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
1262 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
1263 	}
1264 
1265 	printf("%s: 0x%08x\n", __func__, idx);
1266 	return -1;
1267 }
1268 
1269 int
1270 sxiccmu_a80_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1271 {
1272 	struct sxiccmu_clock clock;
1273 	uint32_t parent, parent_freq;
1274 
1275 	switch (idx) {
1276 	case A80_CLK_MMC0:
1277 	case A80_CLK_MMC1:
1278 	case A80_CLK_MMC2:
1279 		clock.sc_iot = sc->sc_iot;
1280 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
1281 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
1282 		parent = A80_CLK_PLL_PERIPH0;
1283 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
1284 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
1285 	}
1286 
1287 	printf("%s: 0x%08x\n", __func__, idx);
1288 	return -1;
1289 }
1290 
1291 int
1292 sxiccmu_h3_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1293 {
1294 	struct sxiccmu_clock clock;
1295 	uint32_t parent, parent_freq;
1296 
1297 	switch (idx) {
1298 	case H3_CLK_MMC0:
1299 	case H3_CLK_MMC1:
1300 	case H3_CLK_MMC2:
1301 		clock.sc_iot = sc->sc_iot;
1302 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
1303 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
1304 		parent = H3_CLK_PLL_PERIPH0;
1305 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
1306 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
1307 	}
1308 
1309 	printf("%s: 0x%08x\n", __func__, idx);
1310 	return -1;
1311 }
1312 
1313 int
1314 sxiccmu_r40_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1315 {
1316 	struct sxiccmu_clock clock;
1317 	uint32_t parent, parent_freq;
1318 
1319 	switch (idx) {
1320 	case R40_CLK_MMC0:
1321 	case R40_CLK_MMC1:
1322 	case R40_CLK_MMC2:
1323 	case R40_CLK_MMC3:
1324 		clock.sc_iot = sc->sc_iot;
1325 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
1326 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
1327 		parent = R40_CLK_PLL_PERIPH0_2X;
1328 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
1329 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
1330 	}
1331 
1332 	printf("%s: 0x%08x\n", __func__, idx);
1333 	return -1;
1334 }
1335 
1336 int
1337 sxiccmu_nop_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1338 {
1339 	printf("%s: 0x%08x\n", __func__, idx);
1340 	return -1;
1341 }
1342 
1343 void
1344 sxiccmu_ccu_enable(void *cookie, uint32_t *cells, int on)
1345 {
1346 	struct sxiccmu_softc *sc = cookie;
1347 	uint32_t idx = cells[0];
1348 	int reg, bit;
1349 
1350 	clock_enable_all(sc->sc_node);
1351 
1352 	if (idx >= sc->sc_ngates ||
1353 	    (sc->sc_gates[idx].reg == 0 && sc->sc_gates[idx].bit == 0)) {
1354 		printf("%s: 0x%08x\n", __func__, cells[0]);
1355 		return;
1356 	}
1357 
1358 	reg = sc->sc_gates[idx].reg;
1359 	bit = sc->sc_gates[idx].bit;
1360 
1361 	if (on)
1362 		SXISET4(sc, reg, (1U << bit));
1363 	else
1364 		SXICLR4(sc, reg, (1U << bit));
1365 }
1366 
1367 void
1368 sxiccmu_ccu_reset(void *cookie, uint32_t *cells, int assert)
1369 {
1370 	struct sxiccmu_softc *sc = cookie;
1371 	uint32_t idx = cells[0];
1372 	int reg, bit;
1373 
1374 	reset_deassert_all(sc->sc_node);
1375 
1376 	if (idx >= sc->sc_nresets ||
1377 	    (sc->sc_resets[idx].reg == 0 && sc->sc_gates[idx].bit == 0)) {
1378 		printf("%s: 0x%08x\n", __func__, cells[0]);
1379 		return;
1380 	}
1381 
1382 	reg = sc->sc_resets[idx].reg;
1383 	bit = sc->sc_resets[idx].bit;
1384 
1385 	if (assert)
1386 		SXICLR4(sc, reg, (1U << bit));
1387 	else
1388 		SXISET4(sc, reg, (1U << bit));
1389 }
1390