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