xref: /openbsd/sys/dev/fdt/sxiccmu.c (revision d415bd75)
1 /*	$OpenBSD: sxiccmu.c,v 1.32 2023/08/15 08:27:30 miod 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/ofw_misc.h>
36 #include <dev/ofw/fdt.h>
37 
38 /* R40 */
39 #define R40_GMAC_CLK_REG		0x0164
40 
41 #ifdef DEBUG_CCMU
42 #define DPRINTF(x)	do { printf x; } while (0)
43 #else
44 #define DPRINTF(x)
45 #endif
46 
47 struct sxiccmu_ccu_bit {
48 	uint16_t reg;
49 	uint8_t bit;
50 	uint8_t parent;
51 };
52 
53 #include "sxiccmu_clocks.h"
54 
55 struct sxiccmu_softc {
56 	struct device		sc_dev;
57 	bus_space_tag_t		sc_iot;
58 	bus_space_handle_t	sc_ioh;
59 	int			sc_node;
60 
61 	const struct sxiccmu_ccu_bit *sc_gates;
62 	int			sc_ngates;
63 	struct clock_device	sc_cd;
64 
65 	const struct sxiccmu_ccu_bit *sc_resets;
66 	int			sc_nresets;
67 	struct reset_device	sc_rd;
68 
69 	uint32_t		(*sc_get_frequency)(struct sxiccmu_softc *,
70 				    uint32_t);
71 	int			(*sc_set_frequency)(struct sxiccmu_softc *,
72 				    uint32_t, uint32_t);
73 };
74 
75 int	sxiccmu_match(struct device *, void *, void *);
76 void	sxiccmu_attach(struct device *, struct device *, void *);
77 
78 const struct cfattach	sxiccmu_ca = {
79 	sizeof (struct sxiccmu_softc), sxiccmu_match, sxiccmu_attach
80 };
81 
82 struct cfdriver sxiccmu_cd = {
83 	NULL, "sxiccmu", DV_DULL
84 };
85 
86 void sxiccmu_attach_clock(struct sxiccmu_softc *, int, int);
87 
88 uint32_t sxiccmu_ccu_get_frequency(void *, uint32_t *);
89 int	sxiccmu_ccu_set_frequency(void *, uint32_t *, uint32_t);
90 void	sxiccmu_ccu_enable(void *, uint32_t *, int);
91 void	sxiccmu_ccu_reset(void *, uint32_t *, int);
92 
93 uint32_t sxiccmu_a10_get_frequency(struct sxiccmu_softc *, uint32_t);
94 int	sxiccmu_a10_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t);
95 uint32_t sxiccmu_a23_get_frequency(struct sxiccmu_softc *, uint32_t);
96 int	sxiccmu_a23_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t);
97 uint32_t sxiccmu_a64_get_frequency(struct sxiccmu_softc *, uint32_t);
98 int	sxiccmu_a64_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t);
99 uint32_t sxiccmu_a80_get_frequency(struct sxiccmu_softc *, uint32_t);
100 int	sxiccmu_a80_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t);
101 uint32_t sxiccmu_h3_get_frequency(struct sxiccmu_softc *, uint32_t);
102 int	sxiccmu_h3_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t);
103 uint32_t sxiccmu_h3_r_get_frequency(struct sxiccmu_softc *, uint32_t);
104 uint32_t sxiccmu_h6_get_frequency(struct sxiccmu_softc *, uint32_t);
105 int	sxiccmu_h6_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t);
106 uint32_t sxiccmu_h6_r_get_frequency(struct sxiccmu_softc *, uint32_t);
107 uint32_t sxiccmu_r40_get_frequency(struct sxiccmu_softc *, uint32_t);
108 int	sxiccmu_r40_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t);
109 uint32_t sxiccmu_v3s_get_frequency(struct sxiccmu_softc *, uint32_t);
110 int	sxiccmu_v3s_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t);
111 uint32_t sxiccmu_nop_get_frequency(struct sxiccmu_softc *, uint32_t);
112 int	sxiccmu_nop_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t);
113 
114 int
115 sxiccmu_match(struct device *parent, void *match, void *aux)
116 {
117 	struct fdt_attach_args *faa = aux;
118 	int node = faa->fa_node;
119 
120 	if (node == OF_finddevice("/clocks")) {
121 		node = OF_parent(node);
122 
123 		return (OF_is_compatible(node, "allwinner,sun4i-a10") ||
124 		    OF_is_compatible(node, "allwinner,sun5i-a10s") ||
125 		    OF_is_compatible(node, "allwinner,sun5i-r8") ||
126 		    OF_is_compatible(node, "allwinner,sun7i-a20") ||
127 		    OF_is_compatible(node, "allwinner,sun8i-a23") ||
128 		    OF_is_compatible(node, "allwinner,sun8i-a33") ||
129 		    OF_is_compatible(node, "allwinner,sun8i-h3") ||
130 		    OF_is_compatible(node, "allwinner,sun8i-v3s") ||
131 		    OF_is_compatible(node, "allwinner,sun9i-a80") ||
132 		    OF_is_compatible(node, "allwinner,sun50i-a64") ||
133 		    OF_is_compatible(node, "allwinner,sun50i-h5"));
134 	}
135 
136 	return (OF_is_compatible(node, "allwinner,sun4i-a10-ccu") ||
137 	    OF_is_compatible(node, "allwinner,sun7i-a20-ccu") ||
138 	    OF_is_compatible(node, "allwinner,sun8i-a23-ccu") ||
139 	    OF_is_compatible(node, "allwinner,sun8i-a23-prcm") ||
140 	    OF_is_compatible(node, "allwinner,sun8i-a33-ccu") ||
141 	    OF_is_compatible(node, "allwinner,sun8i-h3-ccu") ||
142 	    OF_is_compatible(node, "allwinner,sun8i-h3-r-ccu") ||
143 	    OF_is_compatible(node, "allwinner,sun8i-r40-ccu") ||
144 	    OF_is_compatible(node, "allwinner,sun8i-v3s-ccu") ||
145 	    OF_is_compatible(node, "allwinner,sun9i-a80-ccu") ||
146 	    OF_is_compatible(node, "allwinner,sun9i-a80-usb-clks") ||
147 	    OF_is_compatible(node, "allwinner,sun9i-a80-mmc-config-clk") ||
148 	    OF_is_compatible(node, "allwinner,sun50i-a64-ccu") ||
149 	    OF_is_compatible(node, "allwinner,sun50i-a64-r-ccu") ||
150 	    OF_is_compatible(node, "allwinner,sun50i-h5-ccu") ||
151 	    OF_is_compatible(node, "allwinner,sun50i-h6-ccu") ||
152 	    OF_is_compatible(node, "allwinner,sun50i-h6-r-ccu"));
153 }
154 
155 void
156 sxiccmu_attach(struct device *parent, struct device *self, void *aux)
157 {
158 	struct sxiccmu_softc *sc = (struct sxiccmu_softc *)self;
159 	struct fdt_attach_args *faa = aux;
160 	int node = faa->fa_node;
161 
162 	sc->sc_node = faa->fa_node;
163 	sc->sc_iot = faa->fa_iot;
164 	if (faa->fa_nreg > 0 && bus_space_map(sc->sc_iot,
165 	    faa->fa_reg[0].addr, faa->fa_reg[0].size, 0, &sc->sc_ioh))
166 		panic("%s: bus_space_map failed!", __func__);
167 
168 	/* On the R40, the GMAC needs to poke at one of our registers. */
169 	if (OF_is_compatible(node, "allwinner,sun8i-r40-ccu")) {
170 		bus_space_handle_t ioh;
171 
172 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
173 		    R40_GMAC_CLK_REG, 4, &ioh);
174 		regmap_register(faa->fa_node, sc->sc_iot, ioh, 4);
175 	}
176 
177 	printf("\n");
178 
179 	if (OF_is_compatible(node, "allwinner,sun4i-a10-ccu") ||
180 	    OF_is_compatible(node, "allwinner,sun7i-a20-ccu")) {
181 		KASSERT(faa->fa_nreg > 0);
182 		sc->sc_gates = sun4i_a10_gates;
183 		sc->sc_ngates = nitems(sun4i_a10_gates);
184 		sc->sc_resets = sun4i_a10_resets;
185 		sc->sc_nresets = nitems(sun4i_a10_resets);
186 		sc->sc_get_frequency = sxiccmu_a10_get_frequency;
187 		sc->sc_set_frequency = sxiccmu_a10_set_frequency;
188 	} else if (OF_is_compatible(node, "allwinner,sun8i-a23-ccu") ||
189 	    OF_is_compatible(node, "allwinner,sun8i-a33-ccu")) {
190 		KASSERT(faa->fa_nreg > 0);
191 		sc->sc_gates = sun8i_a23_gates;
192 		sc->sc_ngates = nitems(sun8i_a23_gates);
193 		sc->sc_resets = sun8i_a23_resets;
194 		sc->sc_nresets = nitems(sun8i_a23_resets);
195 		sc->sc_get_frequency = sxiccmu_a23_get_frequency;
196 		sc->sc_set_frequency = sxiccmu_a23_set_frequency;
197 	} else if (OF_is_compatible(node, "allwinner,sun8i-h3-ccu") ||
198 	    OF_is_compatible(node, "allwinner,sun50i-h5-ccu")) {
199 		KASSERT(faa->fa_nreg > 0);
200 		sc->sc_gates = sun8i_h3_gates;
201 		sc->sc_ngates = nitems(sun8i_h3_gates);
202 		sc->sc_resets = sun8i_h3_resets;
203 		sc->sc_nresets = nitems(sun8i_h3_resets);
204 		sc->sc_get_frequency = sxiccmu_h3_get_frequency;
205 		sc->sc_set_frequency = sxiccmu_h3_set_frequency;
206 	} else if (OF_is_compatible(node, "allwinner,sun8i-h3-r-ccu") ||
207 	    OF_is_compatible(node, "allwinner,sun50i-a64-r-ccu")) {
208 		KASSERT(faa->fa_nreg > 0);
209 		sc->sc_gates = sun8i_h3_r_gates;
210 		sc->sc_ngates = nitems(sun8i_h3_r_gates);
211 		sc->sc_resets = sun8i_h3_r_resets;
212 		sc->sc_nresets = nitems(sun8i_h3_r_resets);
213 		sc->sc_get_frequency = sxiccmu_h3_r_get_frequency;
214 		sc->sc_set_frequency = sxiccmu_nop_set_frequency;
215 	} else if (OF_is_compatible(node, "allwinner,sun8i-r40-ccu")) {
216 		KASSERT(faa->fa_nreg > 0);
217 		sc->sc_gates = sun8i_r40_gates;
218 		sc->sc_ngates = nitems(sun8i_r40_gates);
219 		sc->sc_resets = sun8i_r40_resets;
220 		sc->sc_nresets = nitems(sun8i_r40_resets);
221 		sc->sc_get_frequency = sxiccmu_r40_get_frequency;
222 		sc->sc_set_frequency = sxiccmu_r40_set_frequency;
223 	} else if (OF_is_compatible(node, "allwinner,sun8i-v3s-ccu")) {
224 		KASSERT(faa->fa_nreg > 0);
225 		sc->sc_gates = sun8i_v3s_gates;
226 		sc->sc_ngates = nitems(sun8i_v3s_gates);
227 		sc->sc_resets = sun8i_v3s_resets;
228 		sc->sc_nresets = nitems(sun8i_v3s_resets);
229 		sc->sc_get_frequency = sxiccmu_v3s_get_frequency;
230 		sc->sc_set_frequency = sxiccmu_v3s_set_frequency;
231 	} else if (OF_is_compatible(node, "allwinner,sun9i-a80-ccu")) {
232 		KASSERT(faa->fa_nreg > 0);
233 		sc->sc_gates = sun9i_a80_gates;
234 		sc->sc_ngates = nitems(sun9i_a80_gates);
235 		sc->sc_resets = sun9i_a80_resets;
236 		sc->sc_nresets = nitems(sun9i_a80_resets);
237 		sc->sc_get_frequency = sxiccmu_a80_get_frequency;
238 		sc->sc_set_frequency = sxiccmu_a80_set_frequency;
239 	} else if (OF_is_compatible(node, "allwinner,sun9i-a80-usb-clks")) {
240 		KASSERT(faa->fa_nreg > 0);
241 		sc->sc_gates = sun9i_a80_usb_gates;
242 		sc->sc_ngates = nitems(sun9i_a80_usb_gates);
243 		sc->sc_resets = sun9i_a80_usb_resets;
244 		sc->sc_nresets = nitems(sun9i_a80_usb_resets);
245 		sc->sc_get_frequency = sxiccmu_nop_get_frequency;
246 		sc->sc_set_frequency = sxiccmu_nop_set_frequency;
247 	} else if (OF_is_compatible(node, "allwinner,sun9i-a80-mmc-config-clk")) {
248 		KASSERT(faa->fa_nreg > 0);
249 		sc->sc_gates = sun9i_a80_mmc_gates;
250 		sc->sc_ngates = nitems(sun9i_a80_mmc_gates);
251 		sc->sc_resets = sun9i_a80_mmc_resets;
252 		sc->sc_nresets = nitems(sun9i_a80_mmc_resets);
253 		sc->sc_get_frequency = sxiccmu_nop_get_frequency;
254 		sc->sc_set_frequency = sxiccmu_nop_set_frequency;
255 	} else if (OF_is_compatible(node, "allwinner,sun50i-a64-ccu")) {
256 		KASSERT(faa->fa_nreg > 0);
257 		sc->sc_gates = sun50i_a64_gates;
258 		sc->sc_ngates = nitems(sun50i_a64_gates);
259 		sc->sc_resets = sun50i_a64_resets;
260 		sc->sc_nresets = nitems(sun50i_a64_resets);
261 		sc->sc_get_frequency = sxiccmu_a64_get_frequency;
262 		sc->sc_set_frequency = sxiccmu_a64_set_frequency;
263 	} else if (OF_is_compatible(node, "allwinner,sun50i-h6-ccu")) {
264 		KASSERT(faa->fa_nreg > 0);
265 		sc->sc_gates = sun50i_h6_gates;
266 		sc->sc_ngates = nitems(sun50i_h6_gates);
267 		sc->sc_resets = sun50i_h6_resets;
268 		sc->sc_nresets = nitems(sun50i_h6_resets);
269 		sc->sc_get_frequency = sxiccmu_h6_get_frequency;
270 		sc->sc_set_frequency = sxiccmu_h6_set_frequency;
271 	} else if (OF_is_compatible(node, "allwinner,sun50i-h6-r-ccu")) {
272 		KASSERT(faa->fa_nreg > 0);
273 		sc->sc_gates = sun50i_h6_r_gates;
274 		sc->sc_ngates = nitems(sun50i_h6_r_gates);
275 		sc->sc_resets = sun50i_h6_r_resets;
276 		sc->sc_nresets = nitems(sun50i_h6_r_resets);
277 		sc->sc_get_frequency = sxiccmu_h6_r_get_frequency;
278 		sc->sc_set_frequency = sxiccmu_nop_set_frequency;
279 	} else {
280 		for (node = OF_child(node); node; node = OF_peer(node))
281 			sxiccmu_attach_clock(sc, node, faa->fa_nreg);
282 	}
283 
284 	if (sc->sc_gates) {
285 		sc->sc_cd.cd_node = sc->sc_node;
286 		sc->sc_cd.cd_cookie = sc;
287 		sc->sc_cd.cd_get_frequency = sxiccmu_ccu_get_frequency;
288 		sc->sc_cd.cd_set_frequency = sxiccmu_ccu_set_frequency;
289 		sc->sc_cd.cd_enable = sxiccmu_ccu_enable;
290 		clock_register(&sc->sc_cd);
291 	}
292 
293 	if (sc->sc_resets) {
294 		sc->sc_rd.rd_node = sc->sc_node;
295 		sc->sc_rd.rd_cookie = sc;
296 		sc->sc_rd.rd_reset = sxiccmu_ccu_reset;
297 		reset_register(&sc->sc_rd);
298 	}
299 }
300 
301 /*
302  * Classic device trees for the Allwinner SoCs have basically a clock
303  * node per register of the clock control unit.  Attaching a separate
304  * driver to each of them would be crazy, so we handle them here.
305  */
306 
307 struct sxiccmu_clock {
308 	int sc_node;
309 	bus_space_tag_t sc_iot;
310 	bus_space_handle_t sc_ioh;
311 
312 	struct clock_device sc_cd;
313 	struct reset_device sc_rd;
314 };
315 
316 struct sxiccmu_device {
317 	const char *compat;
318 	uint32_t (*get_frequency)(void *, uint32_t *);
319 	int	(*set_frequency)(void *, uint32_t *, uint32_t);
320 	void	(*enable)(void *, uint32_t *, int);
321 	void	(*reset)(void *, uint32_t *, int);
322 	bus_size_t offset;
323 };
324 
325 uint32_t sxiccmu_gen_get_frequency(void *, uint32_t *);
326 uint32_t sxiccmu_osc_get_frequency(void *, uint32_t *);
327 uint32_t sxiccmu_pll6_get_frequency(void *, uint32_t *);
328 void	sxiccmu_pll6_enable(void *, uint32_t *, int);
329 uint32_t sxiccmu_apb1_get_frequency(void *, uint32_t *);
330 uint32_t sxiccmu_cpus_get_frequency(void *, uint32_t *);
331 uint32_t sxiccmu_apbs_get_frequency(void *, uint32_t *);
332 int	sxiccmu_gmac_set_frequency(void *, uint32_t *, uint32_t);
333 int	sxiccmu_mmc_set_frequency(void *, uint32_t *, uint32_t);
334 void	sxiccmu_mmc_enable(void *, uint32_t *, int);
335 void	sxiccmu_gate_enable(void *, uint32_t *, int);
336 void	sxiccmu_reset(void *, uint32_t *, int);
337 
338 const struct sxiccmu_device sxiccmu_devices[] = {
339 	{
340 		.compat = "allwinner,sun4i-a10-osc-clk",
341 		.get_frequency = sxiccmu_osc_get_frequency,
342 	},
343 	{
344 		.compat = "allwinner,sun4i-a10-pll6-clk",
345 		.get_frequency = sxiccmu_pll6_get_frequency,
346 		.enable = sxiccmu_pll6_enable
347 	},
348 	{
349 		.compat = "allwinner,sun4i-a10-apb1-clk",
350 		.get_frequency = sxiccmu_apb1_get_frequency,
351 	},
352 	{
353 		.compat = "allwinner,sun4i-a10-ahb-gates-clk",
354 		.get_frequency = sxiccmu_gen_get_frequency,
355 		.enable = sxiccmu_gate_enable
356 	},
357 	{
358 		.compat = "allwinner,sun4i-a10-apb0-gates-clk",
359 		.get_frequency = sxiccmu_gen_get_frequency,
360 		.enable = sxiccmu_gate_enable
361 	},
362 	{
363 		.compat = "allwinner,sun4i-a10-apb1-gates-clk",
364 		.get_frequency = sxiccmu_gen_get_frequency,
365 		.enable = sxiccmu_gate_enable
366 	},
367 	{
368 		.compat = "allwinner,sun4i-a10-mmc-clk",
369 		.set_frequency = sxiccmu_mmc_set_frequency,
370 		.enable = sxiccmu_mmc_enable
371 	},
372 	{
373 		.compat = "allwinner,sun4i-a10-usb-clk",
374 		.get_frequency = sxiccmu_gen_get_frequency,
375 		.enable = sxiccmu_gate_enable,
376 		.reset = sxiccmu_reset
377 	},
378 	{
379 		.compat = "allwinner,sun5i-a10s-ahb-gates-clk",
380 		.get_frequency = sxiccmu_gen_get_frequency,
381 		.enable = sxiccmu_gate_enable
382 	},
383 	{
384 		.compat = "allwinner,sun5i-a10s-apb0-gates-clk",
385 		.get_frequency = sxiccmu_gen_get_frequency,
386 		.enable = sxiccmu_gate_enable
387 	},
388 	{
389 		.compat = "allwinner,sun5i-a10s-apb1-gates-clk",
390 		.get_frequency = sxiccmu_gen_get_frequency,
391 		.enable = sxiccmu_gate_enable
392 	},
393 	{
394 		.compat = "allwinner,sun5i-a13-ahb-gates-clk",
395 		.get_frequency = sxiccmu_gen_get_frequency,
396 		.enable = sxiccmu_gate_enable
397 	},
398 	{
399 		.compat = "allwinner,sun5i-a13-apb0-gates-clk",
400 		.get_frequency = sxiccmu_gen_get_frequency,
401 		.enable = sxiccmu_gate_enable
402 	},
403 	{
404 		.compat = "allwinner,sun5i-a13-apb1-gates-clk",
405 		.get_frequency = sxiccmu_gen_get_frequency,
406 		.enable = sxiccmu_gate_enable
407 	},
408 	{
409 		.compat = "allwinner,sun5i-a13-usb-clk",
410 		.get_frequency = sxiccmu_gen_get_frequency,
411 		.enable = sxiccmu_gate_enable,
412 		.reset = sxiccmu_reset
413 	},
414 	{
415 		.compat = "allwinner,sun6i-a31-ahb1-reset",
416 		.reset = sxiccmu_reset
417 	},
418 	{
419 		.compat = "allwinner,sun6i-a31-clock-reset",
420 		.reset = sxiccmu_reset,
421 		.offset = 0x00b0
422 	},
423 	{
424 		.compat = "allwinner,sun7i-a20-ahb-gates-clk",
425 		.get_frequency = sxiccmu_gen_get_frequency,
426 		.enable = sxiccmu_gate_enable
427 	},
428 	{
429 		.compat = "allwinner,sun7i-a20-apb0-gates-clk",
430 		.get_frequency = sxiccmu_gen_get_frequency,
431 		.enable = sxiccmu_gate_enable
432 	},
433 	{
434 		.compat = "allwinner,sun7i-a20-apb1-gates-clk",
435 		.get_frequency = sxiccmu_gen_get_frequency,
436 		.enable = sxiccmu_gate_enable
437 	},
438 	{
439 		.compat = "allwinner,sun7i-a20-gmac-clk",
440 		.set_frequency = sxiccmu_gmac_set_frequency
441 	},
442 	{
443 		.compat = "allwinner,sun8i-a23-apb0-clk",
444 		.get_frequency = sxiccmu_apbs_get_frequency,
445 		.offset = 0x000c
446 	},
447 	{
448 		.compat = "allwinner,sun8i-a23-ahb1-gates-clk",
449 		.get_frequency = sxiccmu_gen_get_frequency,
450 		.enable = sxiccmu_gate_enable
451 	},
452 	{
453 		.compat = "allwinner,sun8i-a23-apb0-gates-clk",
454 		.get_frequency = sxiccmu_gen_get_frequency,
455 		.enable = sxiccmu_gate_enable,
456 		.offset = 0x0028
457 	},
458 	{
459 		.compat = "allwinner,sun8i-a23-apb1-gates-clk",
460 		.get_frequency = sxiccmu_gen_get_frequency,
461 		.enable = sxiccmu_gate_enable
462 	},
463 	{
464 		.compat = "allwinner,sun8i-a23-apb2-gates-clk",
465 		.get_frequency = sxiccmu_gen_get_frequency,
466 		.enable = sxiccmu_gate_enable
467 	},
468 	{
469 		.compat = "allwinner,sun8i-a23-usb-clk",
470 		.get_frequency = sxiccmu_gen_get_frequency,
471 		.enable = sxiccmu_gate_enable,
472 		.reset = sxiccmu_reset
473 	},
474 	{
475 		.compat = "allwinner,sun8i-h3-apb0-gates-clk",
476 		.get_frequency = sxiccmu_gen_get_frequency,
477 		.enable = sxiccmu_gate_enable
478 	},
479 	{
480 		.compat = "allwinner,sun9i-a80-apb1-clk",
481 		.get_frequency = sxiccmu_apb1_get_frequency,
482 	},
483 	{
484 		.compat = "allwinner,sun9i-a80-ahb0-gates-clk",
485 		.get_frequency = sxiccmu_gen_get_frequency,
486 		.enable = sxiccmu_gate_enable
487 	},
488 	{
489 		.compat = "allwinner,sun9i-a80-ahb1-gates-clk",
490 		.get_frequency = sxiccmu_gen_get_frequency,
491 		.enable = sxiccmu_gate_enable
492 	},
493 	{
494 		.compat = "allwinner,sun9i-a80-ahb2-gates-clk",
495 		.get_frequency = sxiccmu_gen_get_frequency,
496 		.enable = sxiccmu_gate_enable
497 	},
498 	{
499 		.compat = "allwinner,sun9i-a80-apb0-gates-clk",
500 		.get_frequency = sxiccmu_gen_get_frequency,
501 		.enable = sxiccmu_gate_enable
502 	},
503 	{
504 		.compat = "allwinner,sun9i-a80-apb1-gates-clk",
505 		.get_frequency = sxiccmu_gen_get_frequency,
506 		.enable = sxiccmu_gate_enable
507 	},
508 	{
509 		.compat = "allwinner,sun9i-a80-apbs-gates-clk",
510 		.get_frequency = sxiccmu_gen_get_frequency,
511 		.enable = sxiccmu_gate_enable
512 	},
513 	{
514 		.compat = "allwinner,sun9i-a80-cpus-clk",
515 		.get_frequency = sxiccmu_cpus_get_frequency
516 	},
517 	{
518 		.compat = "allwinner,sun9i-a80-mmc-clk",
519 		.set_frequency = sxiccmu_mmc_set_frequency,
520 		.enable = sxiccmu_mmc_enable
521 	},
522 	{
523 		.compat = "allwinner,sun9i-a80-usb-mod-clk",
524 		.get_frequency = sxiccmu_gen_get_frequency,
525 		.enable = sxiccmu_gate_enable,
526 		.reset = sxiccmu_reset
527 	},
528 	{
529 		.compat = "allwinner,sun9i-a80-usb-phy-clk",
530 		.get_frequency = sxiccmu_gen_get_frequency,
531 		.enable = sxiccmu_gate_enable,
532 		.reset = sxiccmu_reset
533 	},
534 };
535 
536 void
537 sxiccmu_attach_clock(struct sxiccmu_softc *sc, int node, int nreg)
538 {
539 	struct sxiccmu_clock *clock;
540 	uint32_t reg[2];
541 	int i, error = ENODEV;
542 
543 	for (i = 0; i < nitems(sxiccmu_devices); i++)
544 		if (OF_is_compatible(node, sxiccmu_devices[i].compat))
545 			break;
546 	if (i == nitems(sxiccmu_devices))
547 		return;
548 
549 	clock = malloc(sizeof(*clock), M_DEVBUF, M_WAITOK);
550 	clock->sc_node = node;
551 
552 	clock->sc_iot = sc->sc_iot;
553 	if (OF_getpropintarray(node, "reg", reg, sizeof(reg)) == sizeof(reg)) {
554 		error = bus_space_map(clock->sc_iot, reg[0], reg[1], 0,
555 		    &clock->sc_ioh);
556 	} else if (nreg > 0) {
557 		error = bus_space_subregion(clock->sc_iot, sc->sc_ioh,
558 		    sxiccmu_devices[i].offset, 4, &clock->sc_ioh);
559 	}
560 	if (error) {
561 		printf("%s: can't map registers", sc->sc_dev.dv_xname);
562 		free(clock, M_DEVBUF, sizeof(*clock));
563 		return;
564 	}
565 
566 	clock->sc_cd.cd_node = node;
567 	clock->sc_cd.cd_cookie = clock;
568 	clock->sc_cd.cd_get_frequency = sxiccmu_devices[i].get_frequency;
569 	clock->sc_cd.cd_set_frequency = sxiccmu_devices[i].set_frequency;
570 	clock->sc_cd.cd_enable = sxiccmu_devices[i].enable;
571 	clock_register(&clock->sc_cd);
572 
573 	if (sxiccmu_devices[i].reset) {
574 		clock->sc_rd.rd_node = node;
575 		clock->sc_rd.rd_cookie = clock;
576 		clock->sc_rd.rd_reset = sxiccmu_devices[i].reset;
577 		reset_register(&clock->sc_rd);
578 	}
579 }
580 
581 /*
582  * A "generic" function that simply gets the clock frequency from the
583  * parent clock.  Useful for clock gating devices that don't scale
584  * their clocks.
585  */
586 uint32_t
587 sxiccmu_gen_get_frequency(void *cookie, uint32_t *cells)
588 {
589 	struct sxiccmu_clock *sc = cookie;
590 
591 	return clock_get_frequency(sc->sc_node, NULL);
592 }
593 
594 uint32_t
595 sxiccmu_osc_get_frequency(void *cookie, uint32_t *cells)
596 {
597 	struct sxiccmu_clock *sc = cookie;
598 
599 	return OF_getpropint(sc->sc_node, "clock-frequency", 24000000);
600 }
601 
602 #define CCU_PLL6_ENABLE			(1U << 31)
603 #define CCU_PLL6_BYPASS_EN		(1U << 30)
604 #define CCU_PLL6_SATA_CLK_EN		(1U << 14)
605 #define CCU_PLL6_FACTOR_N(x)		(((x) >> 8) & 0x1f)
606 #define CCU_PLL6_FACTOR_N_MASK		(0x1f << 8)
607 #define CCU_PLL6_FACTOR_N_SHIFT		8
608 #define CCU_PLL6_FACTOR_K(x)		(((x) >> 4) & 0x3)
609 #define CCU_PLL6_FACTOR_K_MASK		(0x3 << 4)
610 #define CCU_PLL6_FACTOR_K_SHIFT		4
611 #define CCU_PLL6_FACTOR_M(x)		(((x) >> 0) & 0x3)
612 #define CCU_PLL6_FACTOR_M_MASK		(0x3 << 0)
613 #define CCU_PLL6_FACTOR_M_SHIFT		0
614 
615 uint32_t
616 sxiccmu_pll6_get_frequency(void *cookie, uint32_t *cells)
617 {
618 	struct sxiccmu_clock *sc = cookie;
619 	uint32_t reg, k, m, n, freq;
620 	uint32_t idx = cells[0];
621 
622 	/* XXX Assume bypass is disabled. */
623 	reg = SXIREAD4(sc, 0);
624 	k = CCU_PLL6_FACTOR_K(reg) + 1;
625 	m = CCU_PLL6_FACTOR_M(reg) + 1;
626 	n = CCU_PLL6_FACTOR_N(reg);
627 
628 	freq = clock_get_frequency_idx(sc->sc_node, 0);
629 	switch (idx) {
630 	case 0:
631 		return (freq * n * k) / m / 6;		/* pll6_sata */
632 	case 1:
633 		return (freq * n * k) / 2;		/* pll6_other */
634 	case 2:
635 		return (freq * n * k);			/* pll6 */
636 	case 3:
637 		return (freq * n * k) / 4;		/* pll6_div_4 */
638 	}
639 
640 	return 0;
641 }
642 
643 void
644 sxiccmu_pll6_enable(void *cookie, uint32_t *cells, int on)
645 {
646 	struct sxiccmu_clock *sc = cookie;
647 	uint32_t idx = cells[0];
648 	uint32_t reg;
649 
650 	/*
651 	 * Since this clock has several outputs, we never turn it off.
652 	 */
653 
654 	reg = SXIREAD4(sc, 0);
655 	switch (idx) {
656 	case 0:			/* pll6_sata */
657 		if (on)
658 			reg |= CCU_PLL6_SATA_CLK_EN;
659 		else
660 			reg &= ~CCU_PLL6_SATA_CLK_EN;
661 		/* FALLTHROUGH */
662 	case 1:			/* pll6_other */
663 	case 2:			/* pll6 */
664 	case 3:			/* pll6_div_4 */
665 		if (on)
666 			reg |= CCU_PLL6_ENABLE;
667 	}
668 	SXIWRITE4(sc, 0, reg);
669 }
670 
671 #define CCU_APB1_CLK_RAT_N(x)		(((x) >> 16) & 0x3)
672 #define CCU_APB1_CLK_RAT_M(x)		(((x) >> 0) & 0x1f)
673 #define CCU_APB1_CLK_SRC_SEL(x)		(((x) >> 24) & 0x3)
674 
675 uint32_t
676 sxiccmu_apb1_get_frequency(void *cookie, uint32_t *cells)
677 {
678 	struct sxiccmu_clock *sc = cookie;
679 	uint32_t reg, m, n, freq;
680 	int idx;
681 
682 	reg = SXIREAD4(sc, 0);
683 	m = CCU_APB1_CLK_RAT_M(reg);
684 	n = CCU_APB1_CLK_RAT_N(reg);
685 	idx = CCU_APB1_CLK_SRC_SEL(reg);
686 
687 	freq = clock_get_frequency_idx(sc->sc_node, idx);
688 	return freq / (1 << n) / (m + 1);
689 }
690 
691 #define CCU_CPUS_CLK_SRC_SEL(x)		(((x) >> 16) & 0x3)
692 #define CCU_CPUS_POST_DIV(x)		(((x) >> 8) & 0x1f)
693 #define CCU_CPUS_CLK_RATIO(x)		(((x) >> 0) & 0x3)
694 
695 uint32_t
696 sxiccmu_cpus_get_frequency(void *cookie, uint32_t *cells)
697 {
698 	struct sxiccmu_clock *sc = cookie;
699 	uint32_t reg, post_div, clk_ratio, freq;
700 	int idx;
701 
702 	reg = SXIREAD4(sc, 0);
703 	idx = CCU_CPUS_CLK_SRC_SEL(reg);
704 	post_div = (idx == 2 ? CCU_CPUS_POST_DIV(reg): 0);
705 	clk_ratio = CCU_CPUS_CLK_RATIO(reg);
706 
707 	freq = clock_get_frequency_idx(sc->sc_node, idx);
708 	return freq / (clk_ratio + 1) / (post_div + 1);
709 }
710 
711 #define CCU_APBS_CLK_RATIO(x)		(((x) >> 0) & 0x3)
712 
713 uint32_t
714 sxiccmu_apbs_get_frequency(void *cookie, uint32_t *cells)
715 {
716 	struct sxiccmu_clock *sc = cookie;
717 	uint32_t reg, freq;
718 
719 	reg = SXIREAD4(sc, 0);
720 	freq = clock_get_frequency(sc->sc_node, NULL);
721 	return freq / (CCU_APBS_CLK_RATIO(reg) + 1);
722 }
723 
724 #define	CCU_GMAC_CLK_PIT		(1 << 2)
725 #define	CCU_GMAC_CLK_TCS		(3 << 0)
726 #define	CCU_GMAC_CLK_TCS_MII		0
727 #define	CCU_GMAC_CLK_TCS_EXT_125	1
728 #define	CCU_GMAC_CLK_TCS_INT_RGMII	2
729 
730 int
731 sxiccmu_gmac_set_frequency(void *cookie, uint32_t *cells, uint32_t freq)
732 {
733 	struct sxiccmu_clock *sc = cookie;
734 
735 	switch (freq) {
736 	case 25000000:		/* MMI, 25 MHz */
737 		SXICMS4(sc, 0, CCU_GMAC_CLK_PIT|CCU_GMAC_CLK_TCS,
738 		    CCU_GMAC_CLK_TCS_MII);
739 		break;
740 	case 125000000:		/* RGMII, 125 MHz */
741 		SXICMS4(sc, 0, CCU_GMAC_CLK_PIT|CCU_GMAC_CLK_TCS,
742 		    CCU_GMAC_CLK_PIT|CCU_GMAC_CLK_TCS_INT_RGMII);
743 		break;
744 	default:
745 		return -1;
746 	}
747 
748 	return 0;
749 }
750 
751 #define CCU_SDx_SCLK_GATING		(1U << 31)
752 #define CCU_SDx_CLK_SRC_SEL_OSC24M	(0 << 24)
753 #define CCU_SDx_CLK_SRC_SEL_PLL6	(1 << 24)
754 #define CCU_SDx_CLK_SRC_SEL_PLL5	(2 << 24)
755 #define CCU_SDx_CLK_SRC_SEL_MASK	(3 << 24)
756 #define CCU_SDx_CLK_DIV_RATIO_N_MASK	(3 << 16)
757 #define CCU_SDx_CLK_DIV_RATIO_N_SHIFT	16
758 #define CCU_SDx_CLK_DIV_RATIO_M_MASK	(7 << 0)
759 #define CCU_SDx_CLK_DIV_RATIO_M_SHIFT	0
760 
761 int
762 sxiccmu_mmc_do_set_frequency(struct sxiccmu_clock *sc, uint32_t freq,
763     uint32_t parent_freq)
764 {
765 	uint32_t reg, m, n;
766 	uint32_t clk_src;
767 
768 	switch (freq) {
769 	case 400000:
770 		n = 2, m = 15;
771 		clk_src = CCU_SDx_CLK_SRC_SEL_OSC24M;
772 		break;
773 	case 20000000:
774 	case 25000000:
775 	case 26000000:
776 	case 50000000:
777 	case 52000000:
778 		n = 0, m = 0;
779 		clk_src = CCU_SDx_CLK_SRC_SEL_PLL6;
780 		while ((parent_freq / (1 << n) / 16) > freq)
781 			n++;
782 		while ((parent_freq / (1 << n) / (m + 1)) > freq)
783 			m++;
784 		break;
785 	default:
786 		return -1;
787 	}
788 
789 	reg = SXIREAD4(sc, 0);
790 	reg &= ~CCU_SDx_CLK_SRC_SEL_MASK;
791 	reg |= clk_src;
792 	reg &= ~CCU_SDx_CLK_DIV_RATIO_N_MASK;
793 	reg |= n << CCU_SDx_CLK_DIV_RATIO_N_SHIFT;
794 	reg &= ~CCU_SDx_CLK_DIV_RATIO_M_MASK;
795 	reg |= m << CCU_SDx_CLK_DIV_RATIO_M_SHIFT;
796 	SXIWRITE4(sc, 0, reg);
797 
798 	return 0;
799 }
800 
801 int
802 sxiccmu_mmc_set_frequency(void *cookie, uint32_t *cells, uint32_t freq)
803 {
804 	struct sxiccmu_clock *sc = cookie;
805 	uint32_t parent_freq;
806 
807 	if (cells[0] != 0)
808 		return -1;
809 
810 	parent_freq = clock_get_frequency_idx(sc->sc_node, 1);
811 	return sxiccmu_mmc_do_set_frequency(sc, freq, parent_freq);
812 }
813 
814 void
815 sxiccmu_mmc_enable(void *cookie, uint32_t *cells, int on)
816 {
817 	struct sxiccmu_clock *sc = cookie;
818 
819 	if (cells[0] != 0)
820 		return;
821 
822 	if (on)
823 		SXISET4(sc, 0, CCU_SDx_SCLK_GATING);
824 	else
825 		SXICLR4(sc, 0, CCU_SDx_SCLK_GATING);
826 }
827 
828 void
829 sxiccmu_gate_enable(void *cookie, uint32_t *cells, int on)
830 {
831 	struct sxiccmu_clock *sc = cookie;
832 	int reg = cells[0] / 32;
833 	int bit = cells[0] % 32;
834 
835 	if (on) {
836 		clock_enable(sc->sc_node, NULL);
837 		SXISET4(sc, reg * 4, (1U << bit));
838 	} else {
839 		SXICLR4(sc, reg * 4, (1U << bit));
840 		clock_disable(sc->sc_node, NULL);
841 	}
842 }
843 
844 void
845 sxiccmu_reset(void *cookie, uint32_t *cells, int assert)
846 {
847 	struct sxiccmu_clock *sc = cookie;
848 	int reg = cells[0] / 32;
849 	int bit = cells[0] % 32;
850 
851 	if (assert)
852 		SXICLR4(sc, reg * 4, (1U << bit));
853 	else
854 		SXISET4(sc, reg * 4, (1U << bit));
855 }
856 
857 /*
858  * Newer device trees, such as those for the Allwinner H3/A64 have
859  * most of the clock nodes replaced with a single clock control unit
860  * node.
861  */
862 
863 uint32_t
864 sxiccmu_ccu_get_frequency(void *cookie, uint32_t *cells)
865 {
866 	struct sxiccmu_softc *sc = cookie;
867 	uint32_t idx = cells[0];
868 	uint32_t parent;
869 
870 	if (idx < sc->sc_ngates && sc->sc_gates[idx].parent) {
871 		parent = sc->sc_gates[idx].parent;
872 		return sxiccmu_ccu_get_frequency(sc, &parent);
873 	}
874 
875 	return sc->sc_get_frequency(sc, idx);
876 }
877 
878 /* Allwinner A10/A20 */
879 #define A10_PLL1_CFG_REG		0x0000
880 #define A10_PLL1_OUT_EXT_DIVP_MASK	(0x3 << 16)
881 #define A10_PLL1_OUT_EXT_DIVP_SHIFT	16
882 #define A10_PLL1_OUT_EXT_DIVP(x)	(((x) >> 16) & 0x3)
883 #define A10_PLL1_FACTOR_N(x)		(((x) >> 8) & 0x1f)
884 #define A10_PLL1_FACTOR_N_MASK		(0x1f << 8)
885 #define A10_PLL1_FACTOR_N_SHIFT		8
886 #define A10_PLL1_FACTOR_K(x)		(((x) >> 4) & 0x3)
887 #define A10_PLL1_FACTOR_K_MASK		(0x3 << 4)
888 #define A10_PLL1_FACTOR_K_SHIFT		4
889 #define A10_PLL1_FACTOR_M(x)		(((x) >> 0) & 0x3)
890 #define A10_PLL1_FACTOR_M_MASK		(0x3 << 0)
891 #define A10_PLL1_FACTOR_M_SHIFT		0
892 #define A10_CPU_AHB_APB0_CFG_REG	0x0054
893 #define A10_CPU_CLK_SRC_SEL		(0x3 << 16)
894 #define A10_CPU_CLK_SRC_SEL_LOSC	(0x0 << 16)
895 #define A10_CPU_CLK_SRC_SEL_OSC24M	(0x1 << 16)
896 #define A10_CPU_CLK_SRC_SEL_PLL1	(0x2 << 16)
897 #define A10_CPU_CLK_SRC_SEL_200MHZ	(0x3 << 16)
898 #define A10_AHB_CLK_DIV_RATIO(x)	(((x) >> 8) & 0x3)
899 #define A10_AXI_CLK_DIV_RATIO(x)	(((x) >> 0) & 0x3)
900 
901 uint32_t
902 sxiccmu_a10_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
903 {
904 	uint32_t parent;
905 	uint32_t reg, div;
906 	uint32_t k, m, n, p;
907 
908 	switch (idx) {
909 	case A10_CLK_LOSC:
910 		return clock_get_frequency(sc->sc_node, "losc");
911 	case A10_CLK_HOSC:
912 		return clock_get_frequency(sc->sc_node, "hosc");
913 	case A10_CLK_PLL_CORE:
914 		reg = SXIREAD4(sc, A10_PLL1_CFG_REG);
915 		k = A10_PLL1_FACTOR_K(reg) + 1;
916 		m = A10_PLL1_FACTOR_M(reg) + 1;
917 		n = A10_PLL1_FACTOR_N(reg);
918 		p = 1 << A10_PLL1_OUT_EXT_DIVP(reg);
919 		return (24000000 * n * k) / (m * p);
920 	case A10_CLK_PLL_PERIPH_BASE:
921 		/* Not hardcoded, but recommended. */
922 		return 600000000;
923 	case A10_CLK_PLL_PERIPH:
924 		return sxiccmu_a10_get_frequency(sc, A10_CLK_PLL_PERIPH_BASE) * 2;
925 	case A10_CLK_CPU:
926 		reg = SXIREAD4(sc, A10_CPU_AHB_APB0_CFG_REG);
927 		switch (reg & A10_CPU_CLK_SRC_SEL) {
928 		case A10_CPU_CLK_SRC_SEL_LOSC:
929 			parent = A10_CLK_LOSC;
930 			break;
931 		case A10_CPU_CLK_SRC_SEL_OSC24M:
932 			parent = A10_CLK_HOSC;
933 			break;
934 		case A10_CPU_CLK_SRC_SEL_PLL1:
935 			parent = A10_CLK_PLL_CORE;
936 			break;
937 		case A10_CPU_CLK_SRC_SEL_200MHZ:
938 			return 200000000;
939 		}
940 		return sxiccmu_ccu_get_frequency(sc, &parent);
941 	case A10_CLK_AXI:
942 		reg = SXIREAD4(sc, A10_CPU_AHB_APB0_CFG_REG);
943 		div = 1 << A10_AXI_CLK_DIV_RATIO(reg);
944 		parent = A10_CLK_CPU;
945 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
946 	case A10_CLK_AHB:
947 		reg = SXIREAD4(sc, A10_CPU_AHB_APB0_CFG_REG);
948 		div = 1 << A10_AHB_CLK_DIV_RATIO(reg);
949 		parent = A10_CLK_AXI;
950 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
951 	case A10_CLK_APB1:
952 		/* XXX Controlled by a MUX. */
953 		return 24000000;
954 	}
955 
956 	printf("%s: 0x%08x\n", __func__, idx);
957 	return 0;
958 }
959 
960 /* Allwinner A23/A64/H3/H5/R40 */
961 #define CCU_AHB1_APB1_CFG_REG		0x0054
962 #define CCU_AHB1_CLK_SRC_SEL		(3 << 12)
963 #define CCU_AHB1_CLK_SRC_SEL_LOSC	(0 << 12)
964 #define CCU_AHB1_CLK_SRC_SEL_OSC24M	(1 << 12)
965 #define CCU_AHB1_CLK_SRC_SEL_AXI	(2 << 12)
966 #define CCU_AHB1_CLK_SRC_SEL_PERIPH0	(3 << 12)
967 #define CCU_AHB1_PRE_DIV(x)		((((x) >> 6) & 3) + 1)
968 #define CCU_AHB1_CLK_DIV_RATIO(x)	(1 << (((x) >> 4) & 3))
969 #define CCU_AHB2_CFG_REG		0x005c
970 #define CCU_AHB2_CLK_CFG		(3 << 0)
971 
972 uint32_t
973 sxiccmu_a23_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
974 {
975 	uint32_t parent;
976 	uint32_t reg, div;
977 
978 	switch (idx) {
979 	case A23_CLK_LOSC:
980 		return clock_get_frequency(sc->sc_node, "losc");
981 	case A23_CLK_HOSC:
982 		return clock_get_frequency(sc->sc_node, "hosc");
983 	case A23_CLK_PLL_PERIPH:
984 		/* Not hardcoded, but recommended. */
985 		return 600000000;
986 	case A23_CLK_APB2:
987 		/* XXX Controlled by a MUX. */
988 		return 24000000;
989 	case A23_CLK_AHB1:
990 		reg = SXIREAD4(sc, CCU_AHB1_APB1_CFG_REG);
991 		div = CCU_AHB1_CLK_DIV_RATIO(reg);
992 		switch (reg & CCU_AHB1_CLK_SRC_SEL) {
993 		case CCU_AHB1_CLK_SRC_SEL_LOSC:
994 			parent = A23_CLK_LOSC;
995 			break;
996 		case CCU_AHB1_CLK_SRC_SEL_OSC24M:
997 			parent = A23_CLK_HOSC;
998 			break;
999 		case CCU_AHB1_CLK_SRC_SEL_AXI:
1000 			parent = A23_CLK_AXI;
1001 			break;
1002 		case CCU_AHB1_CLK_SRC_SEL_PERIPH0:
1003 			parent = A23_CLK_PLL_PERIPH;
1004 			div *= CCU_AHB1_PRE_DIV(reg);
1005 			break;
1006 		default:
1007 			return 0;
1008 		}
1009 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
1010 	}
1011 
1012 	printf("%s: 0x%08x\n", __func__, idx);
1013 	return 0;
1014 }
1015 
1016 #define A64_PLL_CPUX_CTRL_REG		0x0000
1017 #define A64_PLL_CPUX_LOCK		(1 << 28)
1018 #define A64_PLL_CPUX_OUT_EXT_DIVP(x)	(((x) >> 16) & 0x3)
1019 #define A64_PLL_CPUX_OUT_EXT_DIVP_MASK	(0x3 << 16)
1020 #define A64_PLL_CPUX_FACTOR_N(x)	(((x) >> 8) & 0x1f)
1021 #define A64_PLL_CPUX_FACTOR_N_MASK	(0x1f << 8)
1022 #define A64_PLL_CPUX_FACTOR_N_SHIFT	8
1023 #define A64_PLL_CPUX_FACTOR_K(x)	(((x) >> 4) & 0x3)
1024 #define A64_PLL_CPUX_FACTOR_K_MASK	(0x3 << 4)
1025 #define A64_PLL_CPUX_FACTOR_K_SHIFT	4
1026 #define A64_PLL_CPUX_FACTOR_M(x)	(((x) >> 0) & 0x3)
1027 #define A64_PLL_CPUX_FACTOR_M_MASK	(0x3 << 0)
1028 #define A64_CPUX_AXI_CFG_REG		0x0050
1029 #define A64_CPUX_CLK_SRC_SEL		(0x3 << 16)
1030 #define A64_CPUX_CLK_SRC_SEL_LOSC	(0x0 << 16)
1031 #define A64_CPUX_CLK_SRC_SEL_OSC24M	(0x1 << 16)
1032 #define A64_CPUX_CLK_SRC_SEL_PLL_CPUX	(0x2 << 16)
1033 
1034 uint32_t
1035 sxiccmu_a64_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
1036 {
1037 	uint32_t parent;
1038 	uint32_t reg, div;
1039 	uint32_t k, m, n, p;
1040 
1041 	switch (idx) {
1042 	case A64_CLK_PLL_CPUX:
1043 		reg = SXIREAD4(sc, A64_PLL_CPUX_CTRL_REG);
1044 		k = A64_PLL_CPUX_FACTOR_K(reg) + 1;
1045 		m = A64_PLL_CPUX_FACTOR_M(reg) + 1;
1046 		n = A64_PLL_CPUX_FACTOR_N(reg) + 1;
1047 		p = 1 << A64_PLL_CPUX_OUT_EXT_DIVP(reg);
1048 		return (24000000 * n * k) / (m * p);
1049 	case A64_CLK_CPUX:
1050 		reg = SXIREAD4(sc, A64_CPUX_AXI_CFG_REG);
1051 		switch (reg & A64_CPUX_CLK_SRC_SEL) {
1052 		case A64_CPUX_CLK_SRC_SEL_LOSC:
1053 			parent = A64_CLK_LOSC;
1054 			break;
1055 		case A64_CPUX_CLK_SRC_SEL_OSC24M:
1056 			parent = A64_CLK_HOSC;
1057 			break;
1058 		case A64_CPUX_CLK_SRC_SEL_PLL_CPUX:
1059 			parent = A64_CLK_PLL_CPUX;
1060 			break;
1061 		default:
1062 			return 0;
1063 		}
1064 		return sxiccmu_ccu_get_frequency(sc, &parent);
1065 	case A64_CLK_LOSC:
1066 		return clock_get_frequency(sc->sc_node, "losc");
1067 	case A64_CLK_HOSC:
1068 		return clock_get_frequency(sc->sc_node, "hosc");
1069 	case A64_CLK_PLL_PERIPH0:
1070 		/* Not hardcoded, but recommended. */
1071 		return 600000000;
1072 	case A64_CLK_PLL_PERIPH0_2X:
1073 		return sxiccmu_a64_get_frequency(sc, A64_CLK_PLL_PERIPH0) * 2;
1074 	case A64_CLK_APB2:
1075 		/* XXX Controlled by a MUX. */
1076 		return 24000000;
1077 	case A64_CLK_AHB1:
1078 		reg = SXIREAD4(sc, CCU_AHB1_APB1_CFG_REG);
1079 		div = CCU_AHB1_CLK_DIV_RATIO(reg);
1080 		switch (reg & CCU_AHB1_CLK_SRC_SEL) {
1081 		case CCU_AHB1_CLK_SRC_SEL_LOSC:
1082 			parent = A64_CLK_LOSC;
1083 			break;
1084 		case CCU_AHB1_CLK_SRC_SEL_OSC24M:
1085 			parent = A64_CLK_HOSC;
1086 			break;
1087 		case CCU_AHB1_CLK_SRC_SEL_AXI:
1088 			parent = A64_CLK_AXI;
1089 			break;
1090 		case CCU_AHB1_CLK_SRC_SEL_PERIPH0:
1091 			parent = A64_CLK_PLL_PERIPH0;
1092 			div *= CCU_AHB1_PRE_DIV(reg);
1093 			break;
1094 		default:
1095 			return 0;
1096 		}
1097 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
1098 	case A64_CLK_AHB2:
1099 		reg = SXIREAD4(sc, CCU_AHB2_CFG_REG);
1100 		switch (reg & CCU_AHB2_CLK_CFG) {
1101 		case 0:
1102 			parent = A64_CLK_AHB1;
1103 			div = 1;
1104 			break;
1105 		case 1:
1106 			parent = A64_CLK_PLL_PERIPH0;
1107 			div = 2;
1108 			break;
1109 		default:
1110 			return 0;
1111 		}
1112 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
1113 	}
1114 
1115 	printf("%s: 0x%08x\n", __func__, idx);
1116 	return 0;
1117 }
1118 
1119 #define A80_AHB1_CLK_CFG_REG		0x0064
1120 #define A80_AHB1_SRC_CLK_SELECT		(3 << 24)
1121 #define A80_AHB1_SRC_CLK_SELECT_GTBUS	(0 << 24)
1122 #define A80_AHB1_SRC_CLK_SELECT_PERIPH0	(1 << 24)
1123 #define A80_AHB1_CLK_DIV_RATIO(x)	(1 << ((x) & 0x3))
1124 
1125 uint32_t
1126 sxiccmu_a80_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
1127 {
1128 	uint32_t parent;
1129 	uint32_t reg, div;
1130 
1131 	switch (idx) {
1132 	case A80_CLK_PLL_PERIPH0:
1133 		/* Not hardcoded, but recommended. */
1134 		return 960000000;
1135 	case A80_CLK_AHB1:
1136 		reg = SXIREAD4(sc, A80_AHB1_CLK_CFG_REG);
1137 		div = A80_AHB1_CLK_DIV_RATIO(reg);
1138 		switch (reg & A80_AHB1_SRC_CLK_SELECT) {
1139 		case A80_AHB1_SRC_CLK_SELECT_GTBUS:
1140 			parent = A80_CLK_GTBUS;
1141 			break;
1142 		case A80_AHB1_SRC_CLK_SELECT_PERIPH0:
1143 			parent = A80_CLK_PLL_PERIPH0;
1144 			break;
1145 		default:
1146 			parent = A80_CLK_PLL_PERIPH1;
1147 			break;
1148 		}
1149 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
1150 	case A80_CLK_APB1:
1151 		/* XXX Controlled by a MUX. */
1152 		return 24000000;
1153 	}
1154 
1155 	printf("%s: 0x%08x\n", __func__, idx);
1156 	return 0;
1157 }
1158 
1159 /* Allwinner H3/H5 */
1160 #define H3_PLL_CPUX_CTRL_REG		0x0000
1161 #define H3_PLL_CPUX_ENABLE		(1U << 31)
1162 #define H3_PLL_CPUX_LOCK		(1 << 28)
1163 #define H3_PLL_CPUX_OUT_EXT_DIVP(x)	(((x) >> 16) & 0x3)
1164 #define H3_PLL_CPUX_OUT_EXT_DIVP_MASK	(0x3 << 16)
1165 #define H3_PLL_CPUX_OUT_EXT_DIVP_SHIFT	16
1166 #define H3_PLL_CPUX_FACTOR_N(x)		(((x) >> 8) & 0x1f)
1167 #define H3_PLL_CPUX_FACTOR_N_MASK	(0x1f << 8)
1168 #define H3_PLL_CPUX_FACTOR_N_SHIFT	8
1169 #define H3_PLL_CPUX_FACTOR_K(x)		(((x) >> 4) & 0x3)
1170 #define H3_PLL_CPUX_FACTOR_K_MASK	(0x3 << 4)
1171 #define H3_PLL_CPUX_FACTOR_K_SHIFT	4
1172 #define H3_PLL_CPUX_FACTOR_M(x)		(((x) >> 0) & 0x3)
1173 #define H3_PLL_CPUX_FACTOR_M_MASK	(0x3 << 0)
1174 #define H3_PLL_CPUX_FACTOR_M_SHIFT	0
1175 #define H3_CPUX_AXI_CFG_REG		0x0050
1176 #define H3_CPUX_CLK_SRC_SEL		(0x3 << 16)
1177 #define H3_CPUX_CLK_SRC_SEL_LOSC	(0x0 << 16)
1178 #define H3_CPUX_CLK_SRC_SEL_OSC24M	(0x1 << 16)
1179 #define H3_CPUX_CLK_SRC_SEL_PLL_CPUX	(0x2 << 16)
1180 #define H3_PLL_STABLE_TIME_REG1		0x0204
1181 #define H3_PLL_STABLE_TIME_REG1_TIME(x)	(((x) >> 0) & 0xffff)
1182 
1183 uint32_t
1184 sxiccmu_h3_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
1185 {
1186 	uint32_t parent;
1187 	uint32_t reg, div;
1188 	uint32_t k, m, n, p;
1189 
1190 	switch (idx) {
1191 	case H3_CLK_LOSC:
1192 		return clock_get_frequency(sc->sc_node, "losc");
1193 	case H3_CLK_HOSC:
1194 		return clock_get_frequency(sc->sc_node, "hosc");
1195 	case H3_CLK_PLL_CPUX:
1196 		reg = SXIREAD4(sc, H3_PLL_CPUX_CTRL_REG);
1197 		k = H3_PLL_CPUX_FACTOR_K(reg) + 1;
1198 		m = H3_PLL_CPUX_FACTOR_M(reg) + 1;
1199 		n = H3_PLL_CPUX_FACTOR_N(reg) + 1;
1200 		p = 1 << H3_PLL_CPUX_OUT_EXT_DIVP(reg);
1201 		return (24000000 * n * k) / (m * p);
1202 	case H3_CLK_PLL_PERIPH0:
1203 		/* Not hardcoded, but recommended. */
1204 		return 600000000;
1205 	case H3_CLK_CPUX:
1206 		reg = SXIREAD4(sc, H3_CPUX_AXI_CFG_REG);
1207 		switch (reg & H3_CPUX_CLK_SRC_SEL) {
1208 		case H3_CPUX_CLK_SRC_SEL_LOSC:
1209 			parent = H3_CLK_LOSC;
1210 			break;
1211 		case H3_CPUX_CLK_SRC_SEL_OSC24M:
1212 			parent = H3_CLK_HOSC;
1213 			break;
1214 		case H3_CPUX_CLK_SRC_SEL_PLL_CPUX:
1215 			parent = H3_CLK_PLL_CPUX;
1216 			break;
1217 		default:
1218 			return 0;
1219 		}
1220 		return sxiccmu_ccu_get_frequency(sc, &parent);
1221 	case H3_CLK_APB2:
1222 		/* XXX Controlled by a MUX. */
1223 		return 24000000;
1224 	case H3_CLK_AHB1:
1225 		reg = SXIREAD4(sc, CCU_AHB1_APB1_CFG_REG);
1226 		div = CCU_AHB1_CLK_DIV_RATIO(reg);
1227 		switch (reg & CCU_AHB1_CLK_SRC_SEL) {
1228 		case CCU_AHB1_CLK_SRC_SEL_LOSC:
1229 			parent = H3_CLK_LOSC;
1230 			break;
1231 		case CCU_AHB1_CLK_SRC_SEL_OSC24M:
1232 			parent = H3_CLK_HOSC;
1233 			break;
1234 		case CCU_AHB1_CLK_SRC_SEL_AXI:
1235 			parent = H3_CLK_AXI;
1236 			break;
1237 		case CCU_AHB1_CLK_SRC_SEL_PERIPH0:
1238 			parent = H3_CLK_PLL_PERIPH0;
1239 			div *= CCU_AHB1_PRE_DIV(reg);
1240 			break;
1241 		default:
1242 			return 0;
1243 		}
1244 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
1245 	case H3_CLK_AHB2:
1246 		reg = SXIREAD4(sc, CCU_AHB2_CFG_REG);
1247 		switch (reg & CCU_AHB2_CLK_CFG) {
1248 		case 0:
1249 			parent = H3_CLK_AHB1;
1250 			div = 1;
1251 			break;
1252 		case 1:
1253 			parent = H3_CLK_PLL_PERIPH0;
1254 			div = 2;
1255 			break;
1256 		default:
1257 			return 0;
1258 		}
1259 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
1260 	}
1261 
1262 	printf("%s: 0x%08x\n", __func__, idx);
1263 	return 0;
1264 }
1265 
1266 #define H3_AHB0_CLK_REG			0x0000
1267 #define H3_AHB0_CLK_SRC_SEL		(0x3 << 16)
1268 #define H3_AHB0_CLK_SRC_SEL_OSC32K	(0x0 << 16)
1269 #define H3_AHB0_CLK_SRC_SEL_OSC24M	(0x1 << 16)
1270 #define H3_AHB0_CLK_SRC_SEL_PLL_PERIPH0	(0x2 << 16)
1271 #define H3_AHB0_CLK_SRC_SEL_IOSC	(0x3 << 16)
1272 #define H3_AHB0_CLK_PRE_DIV(x)		((((x) >> 8) & 0x1f) + 1)
1273 #define H3_AHB0_CLK_RATIO(x)		(1 << (((x) >> 4) & 3))
1274 #define H3_APB0_CFG_REG			0x000c
1275 #define H3_APB0_CLK_RATIO(x)		(1 << ((x) & 1))
1276 
1277 uint32_t
1278 sxiccmu_h3_r_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
1279 {
1280 	uint32_t parent;
1281 	uint32_t reg, div;
1282 	uint32_t freq;
1283 
1284 	switch (idx) {
1285 	case H3_R_CLK_AHB0:
1286 		reg = SXIREAD4(sc, H3_AHB0_CLK_REG);
1287 		switch (reg & H3_AHB0_CLK_SRC_SEL) {
1288 		case H3_AHB0_CLK_SRC_SEL_OSC32K:
1289 			freq = clock_get_frequency(sc->sc_node, "losc");
1290 			break;
1291 		case H3_AHB0_CLK_SRC_SEL_OSC24M:
1292 			freq = clock_get_frequency(sc->sc_node, "hosc");
1293 			break;
1294 		case H3_AHB0_CLK_SRC_SEL_PLL_PERIPH0:
1295 			freq = clock_get_frequency(sc->sc_node, "pll-periph");
1296 			break;
1297 		case H3_AHB0_CLK_SRC_SEL_IOSC:
1298 			freq = clock_get_frequency(sc->sc_node, "iosc");
1299 			break;
1300 		}
1301 		div = H3_AHB0_CLK_PRE_DIV(reg) * H3_AHB0_CLK_RATIO(reg);
1302 		return freq / div;
1303 	case H3_R_CLK_APB0:
1304 		reg = SXIREAD4(sc, H3_APB0_CFG_REG);
1305 		div = H3_APB0_CLK_RATIO(reg);
1306 		parent = H3_R_CLK_AHB0;
1307 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
1308 	}
1309 
1310 	printf("%s: 0x%08x\n", __func__, idx);
1311 	return 0;
1312 }
1313 
1314 /* Allwinner H6 */
1315 #define H6_AHB3_CFG_REG		0x051c
1316 #define H6_AHB3_CLK_FACTOR_N(x)	(((x) >> 8) & 0x3)
1317 #define H6_AHB3_CLK_FACTOR_M(x)	(((x) >> 0) & 0x3)
1318 
1319 uint32_t
1320 sxiccmu_h6_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
1321 {
1322 	uint32_t reg, m, n;
1323 	uint32_t freq;
1324 
1325 	switch (idx) {
1326 	case H6_CLK_PLL_PERIPH0:
1327 		/* Not hardcoded, but recommended. */
1328 		return 600000000;
1329 	case H6_CLK_PLL_PERIPH0_2X:
1330 		return sxiccmu_h6_get_frequency(sc, H6_CLK_PLL_PERIPH0) * 2;
1331 	case H6_CLK_AHB3:
1332 		reg = SXIREAD4(sc, H6_AHB3_CFG_REG);
1333 		/* assume PLL_PERIPH0 source */
1334 		freq = sxiccmu_h6_get_frequency(sc, H6_CLK_PLL_PERIPH0);
1335 		m = H6_AHB3_CLK_FACTOR_M(reg) + 1;
1336 		n = 1 << H6_AHB3_CLK_FACTOR_N(reg);
1337 		return freq / (m * n);
1338 	case H6_CLK_APB2:
1339 		/* XXX Controlled by a MUX. */
1340 		return 24000000;
1341 		break;
1342 	}
1343 
1344 	printf("%s: 0x%08x\n", __func__, idx);
1345 	return 0;
1346 }
1347 
1348 uint32_t
1349 sxiccmu_h6_r_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
1350 {
1351 	switch (idx) {
1352 	case H6_R_CLK_APB2:
1353 		/* XXX Controlled by a MUX. */
1354 		return 24000000;
1355 		break;
1356 	}
1357 
1358 	printf("%s: 0x%08x\n", __func__, idx);
1359 	return 0;
1360 }
1361 
1362 uint32_t
1363 sxiccmu_r40_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
1364 {
1365 	uint32_t parent;
1366 	uint32_t reg, div;
1367 
1368 	switch (idx) {
1369 	case R40_CLK_LOSC:
1370 		return clock_get_frequency(sc->sc_node, "losc");
1371 	case R40_CLK_HOSC:
1372 		return clock_get_frequency(sc->sc_node, "hosc");
1373 	case R40_CLK_PLL_PERIPH0:
1374 		/* Not hardcoded, but recommended. */
1375 		return 600000000;
1376 	case R40_CLK_PLL_PERIPH0_2X:
1377 		return sxiccmu_r40_get_frequency(sc, R40_CLK_PLL_PERIPH0) * 2;
1378 	case R40_CLK_AHB1:
1379 		reg = SXIREAD4(sc, CCU_AHB1_APB1_CFG_REG);
1380 		div = CCU_AHB1_CLK_DIV_RATIO(reg);
1381 		switch (reg & CCU_AHB1_CLK_SRC_SEL) {
1382 		case CCU_AHB1_CLK_SRC_SEL_LOSC:
1383 			parent = R40_CLK_LOSC;
1384 			break;
1385 		case CCU_AHB1_CLK_SRC_SEL_OSC24M:
1386 			parent = R40_CLK_HOSC;
1387 			break;
1388 		case CCU_AHB1_CLK_SRC_SEL_AXI:
1389 			parent = R40_CLK_AXI;
1390 			break;
1391 		case CCU_AHB1_CLK_SRC_SEL_PERIPH0:
1392 			parent = R40_CLK_PLL_PERIPH0;
1393 			div *= CCU_AHB1_PRE_DIV(reg);
1394 			break;
1395 		}
1396 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
1397 	case R40_CLK_APB2:
1398 		/* XXX Controlled by a MUX. */
1399 		return 24000000;
1400 	}
1401 
1402 	printf("%s: 0x%08x\n", __func__, idx);
1403 	return 0;
1404 }
1405 
1406 uint32_t
1407 sxiccmu_v3s_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
1408 {
1409 	uint32_t parent;
1410 	uint32_t reg, div;
1411 
1412 	switch (idx) {
1413 	case V3S_CLK_LOSC:
1414 		return clock_get_frequency(sc->sc_node, "losc");
1415 	case V3S_CLK_HOSC:
1416 		return clock_get_frequency(sc->sc_node, "hosc");
1417 	case V3S_CLK_PLL_PERIPH0:
1418 		/* Not hardcoded, but recommended. */
1419 		return 600000000;
1420 	case V3S_CLK_APB2:
1421 		/* XXX Controlled by a MUX. */
1422 		return 24000000;
1423 	case V3S_CLK_AHB1:
1424 		reg = SXIREAD4(sc, CCU_AHB1_APB1_CFG_REG);
1425 		div = CCU_AHB1_CLK_DIV_RATIO(reg);
1426 		switch (reg & CCU_AHB1_CLK_SRC_SEL) {
1427 		case CCU_AHB1_CLK_SRC_SEL_LOSC:
1428 			parent = V3S_CLK_LOSC;
1429 			break;
1430 		case CCU_AHB1_CLK_SRC_SEL_OSC24M:
1431 			parent = V3S_CLK_HOSC;
1432 			break;
1433 		case CCU_AHB1_CLK_SRC_SEL_AXI:
1434 			parent = V3S_CLK_AXI;
1435 			break;
1436 		case CCU_AHB1_CLK_SRC_SEL_PERIPH0:
1437 			parent = V3S_CLK_PLL_PERIPH0;
1438 			div *= CCU_AHB1_PRE_DIV(reg);
1439 			break;
1440 		default:
1441 			return 0;
1442 		}
1443 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
1444 	case V3S_CLK_AHB2:
1445 		reg = SXIREAD4(sc, CCU_AHB2_CFG_REG);
1446 		switch (reg & CCU_AHB2_CLK_CFG) {
1447 		case 0:
1448 			parent = V3S_CLK_AHB1;
1449 			div = 1;
1450 			break;
1451 		case 1:
1452 			parent = V3S_CLK_PLL_PERIPH0;
1453 			div = 2;
1454 			break;
1455 		default:
1456 			return 0;
1457 		}
1458 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
1459 	}
1460 
1461 	printf("%s: 0x%08x\n", __func__, idx);
1462 	return 0;
1463 }
1464 
1465 uint32_t
1466 sxiccmu_nop_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
1467 {
1468 	printf("%s: 0x%08x\n", __func__, idx);
1469 	return 0;
1470 }
1471 
1472 int
1473 sxiccmu_ccu_set_frequency(void *cookie, uint32_t *cells, uint32_t freq)
1474 {
1475 	struct sxiccmu_softc *sc = cookie;
1476 	uint32_t idx = cells[0];
1477 
1478 	return sc->sc_set_frequency(sc, idx, freq);
1479 }
1480 
1481 int
1482 sxiccmu_a10_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1483 {
1484 	struct sxiccmu_clock clock;
1485 	uint32_t parent, parent_freq;
1486 	uint32_t reg;
1487 	int k, n;
1488 	int error;
1489 
1490 	switch (idx) {
1491 	case A10_CLK_PLL_CORE:
1492 		k = 1; n = 32;
1493 		while (k <= 4 && (24000000 * n * k) < freq)
1494 			k++;
1495 		while (n >= 1 && (24000000 * n * k) > freq)
1496 			n--;
1497 
1498 		reg = SXIREAD4(sc, A10_PLL1_CFG_REG);
1499 		reg &= ~A10_PLL1_OUT_EXT_DIVP_MASK;
1500 		reg &= ~A10_PLL1_FACTOR_N_MASK;
1501 		reg &= ~A10_PLL1_FACTOR_K_MASK;
1502 		reg &= ~A10_PLL1_FACTOR_M_MASK;
1503 		reg |= (n << A10_PLL1_FACTOR_N_SHIFT);
1504 		reg |= ((k - 1) << A10_PLL1_FACTOR_K_SHIFT);
1505 		SXIWRITE4(sc, A10_PLL1_CFG_REG, reg);
1506 
1507 		/* No need to wait PLL to lock? */
1508 
1509 		return 0;
1510 	case A10_CLK_CPU:
1511 		/* Switch to 24 MHz clock. */
1512 		reg = SXIREAD4(sc, A10_CPU_AHB_APB0_CFG_REG);
1513 		reg &= ~A10_CPU_CLK_SRC_SEL;
1514 		reg |= A10_CPU_CLK_SRC_SEL_OSC24M;
1515 		SXIWRITE4(sc, A10_CPU_AHB_APB0_CFG_REG, reg);
1516 
1517 		error = sxiccmu_a10_set_frequency(sc, A10_CLK_PLL_CORE, freq);
1518 
1519 		/* Switch back to PLL. */
1520 		reg = SXIREAD4(sc, A10_CPU_AHB_APB0_CFG_REG);
1521 		reg &= ~A10_CPU_CLK_SRC_SEL;
1522 		reg |= A10_CPU_CLK_SRC_SEL_PLL1;
1523 		SXIWRITE4(sc, A10_CPU_AHB_APB0_CFG_REG, reg);
1524 		return error;
1525 	case A10_CLK_MMC0:
1526 	case A10_CLK_MMC1:
1527 	case A10_CLK_MMC2:
1528 	case A10_CLK_MMC3:
1529 		clock.sc_iot = sc->sc_iot;
1530 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
1531 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
1532 		parent = A10_CLK_PLL_PERIPH;
1533 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
1534 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
1535 	}
1536 
1537 	printf("%s: 0x%08x\n", __func__, idx);
1538 	return -1;
1539 }
1540 
1541 int
1542 sxiccmu_a23_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1543 {
1544 	struct sxiccmu_clock clock;
1545 	uint32_t parent, parent_freq;
1546 
1547 	switch (idx) {
1548 	case A23_CLK_MMC0:
1549 	case A23_CLK_MMC1:
1550 	case A23_CLK_MMC2:
1551 		clock.sc_iot = sc->sc_iot;
1552 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
1553 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
1554 		parent = A23_CLK_PLL_PERIPH;
1555 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
1556 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
1557 	}
1558 
1559 	printf("%s: 0x%08x\n", __func__, idx);
1560 	return -1;
1561 }
1562 
1563 int
1564 sxiccmu_a64_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1565 {
1566 	struct sxiccmu_clock clock;
1567 	uint32_t parent, parent_freq;
1568 	uint32_t reg;
1569 	int k, n;
1570 	int error;
1571 
1572 	switch (idx) {
1573 	case A64_CLK_PLL_CPUX:
1574 		k = 1; n = 32;
1575 		while (k <= 4 && (24000000 * n * k) < freq)
1576 			k++;
1577 		while (n >= 1 && (24000000 * n * k) > freq)
1578 			n--;
1579 
1580 		reg = SXIREAD4(sc, A64_PLL_CPUX_CTRL_REG);
1581 		reg &= ~A64_PLL_CPUX_OUT_EXT_DIVP_MASK;
1582 		reg &= ~A64_PLL_CPUX_FACTOR_N_MASK;
1583 		reg &= ~A64_PLL_CPUX_FACTOR_K_MASK;
1584 		reg &= ~A64_PLL_CPUX_FACTOR_M_MASK;
1585 		reg |= ((n - 1) << A64_PLL_CPUX_FACTOR_N_SHIFT);
1586 		reg |= ((k - 1) << A64_PLL_CPUX_FACTOR_K_SHIFT);
1587 		SXIWRITE4(sc, A64_PLL_CPUX_CTRL_REG, reg);
1588 
1589 		/* Wait for PLL to lock. */
1590 		while ((SXIREAD4(sc, A64_PLL_CPUX_CTRL_REG) &
1591 		    A64_PLL_CPUX_LOCK) == 0) {
1592 			delay(200);
1593 		}
1594 
1595 		return 0;
1596 	case A64_CLK_CPUX:
1597 		/* Switch to 24 MHz clock. */
1598 		reg = SXIREAD4(sc, A64_CPUX_AXI_CFG_REG);
1599 		reg &= ~A64_CPUX_CLK_SRC_SEL;
1600 		reg |= A64_CPUX_CLK_SRC_SEL_OSC24M;
1601 		SXIWRITE4(sc, A64_CPUX_AXI_CFG_REG, reg);
1602 
1603 		error = sxiccmu_a64_set_frequency(sc, A64_CLK_PLL_CPUX, freq);
1604 
1605 		/* Switch back to PLL. */
1606 		reg = SXIREAD4(sc, A64_CPUX_AXI_CFG_REG);
1607 		reg &= ~A64_CPUX_CLK_SRC_SEL;
1608 		reg |= A64_CPUX_CLK_SRC_SEL_PLL_CPUX;
1609 		SXIWRITE4(sc, A64_CPUX_AXI_CFG_REG, reg);
1610 		return error;
1611 	case A64_CLK_MMC0:
1612 	case A64_CLK_MMC1:
1613 	case A64_CLK_MMC2:
1614 		clock.sc_iot = sc->sc_iot;
1615 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
1616 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
1617 		parent = A64_CLK_PLL_PERIPH0_2X;
1618 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
1619 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
1620 	}
1621 
1622 	printf("%s: 0x%08x\n", __func__, idx);
1623 	return -1;
1624 }
1625 
1626 int
1627 sxiccmu_a80_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1628 {
1629 	struct sxiccmu_clock clock;
1630 	uint32_t parent, parent_freq;
1631 
1632 	switch (idx) {
1633 	case A80_CLK_MMC0:
1634 	case A80_CLK_MMC1:
1635 	case A80_CLK_MMC2:
1636 		clock.sc_iot = sc->sc_iot;
1637 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
1638 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
1639 		parent = A80_CLK_PLL_PERIPH0;
1640 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
1641 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
1642 	}
1643 
1644 	printf("%s: 0x%08x\n", __func__, idx);
1645 	return -1;
1646 }
1647 
1648 int
1649 sxiccmu_h3_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1650 {
1651 	struct sxiccmu_clock clock;
1652 	uint32_t parent, parent_freq;
1653 	uint32_t reg, lock_time;
1654 	int k, n;
1655 	int error;
1656 
1657 	switch (idx) {
1658 	case H3_CLK_PLL_CPUX:
1659 		k = 1; n = 32;
1660 		while (k <= 4 && (24000000 * n * k) < freq)
1661 			k++;
1662 		while (n >= 1 && (24000000 * n * k) > freq)
1663 			n--;
1664 
1665 		/* Gate the PLL first */
1666 		reg = SXIREAD4(sc, H3_PLL_CPUX_CTRL_REG);
1667 		reg &= ~H3_PLL_CPUX_ENABLE;
1668 		SXIWRITE4(sc, H3_PLL_CPUX_CTRL_REG, reg);
1669 
1670 		/* Set factors and external divider. */
1671 		reg &= ~H3_PLL_CPUX_OUT_EXT_DIVP_MASK;
1672 		reg &= ~H3_PLL_CPUX_FACTOR_N_MASK;
1673 		reg &= ~H3_PLL_CPUX_FACTOR_K_MASK;
1674 		reg &= ~H3_PLL_CPUX_FACTOR_M_MASK;
1675 		reg |= ((n - 1) << H3_PLL_CPUX_FACTOR_N_SHIFT);
1676 		reg |= ((k - 1) << H3_PLL_CPUX_FACTOR_K_SHIFT);
1677 		SXIWRITE4(sc, H3_PLL_CPUX_CTRL_REG, reg);
1678 
1679 		/* Ungate the PLL */
1680 		reg |= H3_PLL_CPUX_ENABLE;
1681 		SXIWRITE4(sc, H3_PLL_CPUX_CTRL_REG, reg);
1682 
1683 		/* Wait for PLL to lock. (LOCK flag is unreliable) */
1684 		lock_time = SXIREAD4(sc, H3_PLL_STABLE_TIME_REG1);
1685 		delay(H3_PLL_STABLE_TIME_REG1_TIME(lock_time));
1686 
1687 		return 0;
1688 	case H3_CLK_CPUX:
1689 		/* Switch to 24 MHz clock. */
1690 		reg = SXIREAD4(sc, H3_CPUX_AXI_CFG_REG);
1691 		reg &= ~H3_CPUX_CLK_SRC_SEL;
1692 		reg |= H3_CPUX_CLK_SRC_SEL_OSC24M;
1693 		SXIWRITE4(sc, H3_CPUX_AXI_CFG_REG, reg);
1694 		/* Must wait at least 8 cycles of the current clock. */
1695 		delay(1);
1696 
1697 		error = sxiccmu_h3_set_frequency(sc, H3_CLK_PLL_CPUX, freq);
1698 
1699 		/* Switch back to PLL. */
1700 		reg = SXIREAD4(sc, H3_CPUX_AXI_CFG_REG);
1701 		reg &= ~H3_CPUX_CLK_SRC_SEL;
1702 		reg |= H3_CPUX_CLK_SRC_SEL_PLL_CPUX;
1703 		SXIWRITE4(sc, H3_CPUX_AXI_CFG_REG, reg);
1704 		/* Must wait at least 8 cycles of the current clock. */
1705 		delay(1);
1706 		return error;
1707 	case H3_CLK_MMC0:
1708 	case H3_CLK_MMC1:
1709 	case H3_CLK_MMC2:
1710 		clock.sc_iot = sc->sc_iot;
1711 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
1712 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
1713 		parent = H3_CLK_PLL_PERIPH0;
1714 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
1715 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
1716 	}
1717 
1718 	printf("%s: 0x%08x\n", __func__, idx);
1719 	return -1;
1720 }
1721 
1722 #define H6_SMHC0_CLK_REG		0x0830
1723 #define H6_SMHC1_CLK_REG		0x0834
1724 #define H6_SMHC2_CLK_REG		0x0838
1725 #define H6_SMHC_CLK_SRC_SEL			(0x3 << 24)
1726 #define H6_SMHC_CLK_SRC_SEL_OSC24M		(0x0 << 24)
1727 #define H6_SMHC_CLK_SRC_SEL_PLL_PERIPH0_2X	(0x1 << 24)
1728 #define H6_SMHC_FACTOR_N_MASK			(0x3 << 8)
1729 #define H6_SMHC_FACTOR_N_SHIFT			8
1730 #define H6_SMHC_FACTOR_M_MASK			(0xf << 0)
1731 #define H6_SMHC_FACTOR_M_SHIFT			0
1732 
1733 int
1734 sxiccmu_h6_mmc_set_frequency(struct sxiccmu_softc *sc, bus_size_t offset,
1735     uint32_t freq)
1736 {
1737 	uint32_t parent_freq;
1738 	uint32_t reg, m, n;
1739 	uint32_t clk_src;
1740 
1741 	switch (freq) {
1742 	case 400000:
1743 		n = 2, m = 15;
1744 		clk_src = H6_SMHC_CLK_SRC_SEL_OSC24M;
1745 		break;
1746 	case 20000000:
1747 	case 25000000:
1748 	case 26000000:
1749 	case 50000000:
1750 	case 52000000:
1751 		n = 0, m = 0;
1752 		clk_src = H6_SMHC_CLK_SRC_SEL_PLL_PERIPH0_2X;
1753 		parent_freq =
1754 		    sxiccmu_h6_get_frequency(sc, H6_CLK_PLL_PERIPH0_2X);
1755 		while ((parent_freq / (1 << n) / 16) > freq)
1756 			n++;
1757 		while ((parent_freq / (1 << n) / (m + 1)) > freq)
1758 			m++;
1759 		break;
1760 	default:
1761 		return -1;
1762 	}
1763 
1764 	reg = SXIREAD4(sc, offset);
1765 	reg &= ~H6_SMHC_CLK_SRC_SEL;
1766 	reg |= clk_src;
1767 	reg &= ~H6_SMHC_FACTOR_N_MASK;
1768 	reg |= n << H6_SMHC_FACTOR_N_SHIFT;
1769 	reg &= ~H6_SMHC_FACTOR_M_MASK;
1770 	reg |= m << H6_SMHC_FACTOR_M_SHIFT;
1771 	SXIWRITE4(sc, offset, reg);
1772 
1773 	return 0;
1774 }
1775 
1776 int
1777 sxiccmu_h6_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1778 {
1779 	switch (idx) {
1780 	case H6_CLK_MMC0:
1781 		return sxiccmu_h6_mmc_set_frequency(sc, H6_SMHC0_CLK_REG, freq);
1782 	case H6_CLK_MMC1:
1783 		return sxiccmu_h6_mmc_set_frequency(sc, H6_SMHC1_CLK_REG, freq);
1784 	case H6_CLK_MMC2:
1785 		return sxiccmu_h6_mmc_set_frequency(sc, H6_SMHC2_CLK_REG, freq);
1786 	}
1787 
1788 	printf("%s: 0x%08x\n", __func__, idx);
1789 	return -1;
1790 }
1791 
1792 int
1793 sxiccmu_r40_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1794 {
1795 	struct sxiccmu_clock clock;
1796 	uint32_t parent, parent_freq;
1797 
1798 	switch (idx) {
1799 	case R40_CLK_MMC0:
1800 	case R40_CLK_MMC1:
1801 	case R40_CLK_MMC2:
1802 	case R40_CLK_MMC3:
1803 		clock.sc_iot = sc->sc_iot;
1804 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
1805 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
1806 		parent = R40_CLK_PLL_PERIPH0_2X;
1807 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
1808 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
1809 	}
1810 
1811 	printf("%s: 0x%08x\n", __func__, idx);
1812 	return -1;
1813 }
1814 
1815 int
1816 sxiccmu_v3s_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1817 {
1818 	struct sxiccmu_clock clock;
1819 	uint32_t parent, parent_freq;
1820 
1821 	switch (idx) {
1822 	case V3S_CLK_MMC0:
1823 	case V3S_CLK_MMC1:
1824 	case V3S_CLK_MMC2:
1825 		clock.sc_iot = sc->sc_iot;
1826 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
1827 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
1828 		parent = V3S_CLK_PLL_PERIPH0;
1829 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
1830 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
1831 	}
1832 
1833 	printf("%s: 0x%08x\n", __func__, idx);
1834 	return -1;
1835 }
1836 
1837 int
1838 sxiccmu_nop_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1839 {
1840 	printf("%s: 0x%08x\n", __func__, idx);
1841 	return -1;
1842 }
1843 
1844 void
1845 sxiccmu_ccu_enable(void *cookie, uint32_t *cells, int on)
1846 {
1847 	struct sxiccmu_softc *sc = cookie;
1848 	uint32_t idx = cells[0];
1849 	int reg, bit;
1850 
1851 	clock_enable_all(sc->sc_node);
1852 
1853 	if (idx >= sc->sc_ngates ||
1854 	    (sc->sc_gates[idx].reg == 0 && sc->sc_gates[idx].bit == 0)) {
1855 		printf("%s: 0x%08x\n", __func__, cells[0]);
1856 		return;
1857 	}
1858 
1859 	/* If the clock can't be gated, simply return. */
1860 	if (sc->sc_gates[idx].reg == 0xffff && sc->sc_gates[idx].bit == 0xff)
1861 		return;
1862 
1863 	reg = sc->sc_gates[idx].reg;
1864 	bit = sc->sc_gates[idx].bit;
1865 
1866 	if (on)
1867 		SXISET4(sc, reg, (1U << bit));
1868 	else
1869 		SXICLR4(sc, reg, (1U << bit));
1870 }
1871 
1872 void
1873 sxiccmu_ccu_reset(void *cookie, uint32_t *cells, int assert)
1874 {
1875 	struct sxiccmu_softc *sc = cookie;
1876 	uint32_t idx = cells[0];
1877 	int reg, bit;
1878 
1879 	reset_deassert_all(sc->sc_node);
1880 
1881 	if (idx >= sc->sc_nresets ||
1882 	    (sc->sc_resets[idx].reg == 0 && sc->sc_gates[idx].bit == 0)) {
1883 		printf("%s: 0x%08x\n", __func__, cells[0]);
1884 		return;
1885 	}
1886 
1887 	reg = sc->sc_resets[idx].reg;
1888 	bit = sc->sc_resets[idx].bit;
1889 
1890 	if (assert)
1891 		SXICLR4(sc, reg, (1U << bit));
1892 	else
1893 		SXISET4(sc, reg, (1U << bit));
1894 }
1895