xref: /openbsd-src/sys/dev/fdt/sxiccmu.c (revision 1a8dbaac879b9f3335ad7fb25429ce63ac1d6bac)
1 /*	$OpenBSD: sxiccmu.c,v 1.28 2020/08/30 05:23:49 uaa 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 	struct sxiccmu_ccu_bit	*sc_gates;
62 	int			sc_ngates;
63 	struct clock_device	sc_cd;
64 
65 	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 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 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		(1 << 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 uint32_t
1315 sxiccmu_h6_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
1316 {
1317 	switch (idx) {
1318 	case H6_CLK_PLL_PERIPH0:
1319 		/* Not hardcoded, but recommended. */
1320 		return 600000000;
1321 	case H6_CLK_PLL_PERIPH0_2X:
1322 		return sxiccmu_h6_get_frequency(sc, H6_CLK_PLL_PERIPH0) * 2;
1323 	case H6_CLK_APB2:
1324 		/* XXX Controlled by a MUX. */
1325 		return 24000000;
1326 		break;
1327 	}
1328 
1329 	printf("%s: 0x%08x\n", __func__, idx);
1330 	return 0;
1331 }
1332 
1333 uint32_t
1334 sxiccmu_h6_r_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
1335 {
1336 	switch (idx) {
1337 	case H6_R_CLK_APB2:
1338 		/* XXX Controlled by a MUX. */
1339 		return 24000000;
1340 		break;
1341 	}
1342 
1343 	printf("%s: 0x%08x\n", __func__, idx);
1344 	return 0;
1345 }
1346 
1347 uint32_t
1348 sxiccmu_r40_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
1349 {
1350 	uint32_t parent;
1351 	uint32_t reg, div;
1352 
1353 	switch (idx) {
1354 	case R40_CLK_LOSC:
1355 		return clock_get_frequency(sc->sc_node, "losc");
1356 	case R40_CLK_HOSC:
1357 		return clock_get_frequency(sc->sc_node, "hosc");
1358 	case R40_CLK_PLL_PERIPH0:
1359 		/* Not hardcoded, but recommended. */
1360 		return 600000000;
1361 	case R40_CLK_PLL_PERIPH0_2X:
1362 		return sxiccmu_r40_get_frequency(sc, R40_CLK_PLL_PERIPH0) * 2;
1363 	case R40_CLK_AHB1:
1364 		reg = SXIREAD4(sc, CCU_AHB1_APB1_CFG_REG);
1365 		div = CCU_AHB1_CLK_DIV_RATIO(reg);
1366 		switch (reg & CCU_AHB1_CLK_SRC_SEL) {
1367 		case CCU_AHB1_CLK_SRC_SEL_LOSC:
1368 			parent = R40_CLK_LOSC;
1369 			break;
1370 		case CCU_AHB1_CLK_SRC_SEL_OSC24M:
1371 			parent = R40_CLK_HOSC;
1372 			break;
1373 		case CCU_AHB1_CLK_SRC_SEL_AXI:
1374 			parent = R40_CLK_AXI;
1375 			break;
1376 		case CCU_AHB1_CLK_SRC_SEL_PERIPH0:
1377 			parent = R40_CLK_PLL_PERIPH0;
1378 			div *= CCU_AHB1_PRE_DIV(reg);
1379 			break;
1380 		}
1381 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
1382 	case R40_CLK_APB2:
1383 		/* XXX Controlled by a MUX. */
1384 		return 24000000;
1385 	}
1386 
1387 	printf("%s: 0x%08x\n", __func__, idx);
1388 	return 0;
1389 }
1390 
1391 uint32_t
1392 sxiccmu_v3s_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
1393 {
1394 	uint32_t parent;
1395 	uint32_t reg, div;
1396 
1397 	switch (idx) {
1398 	case V3S_CLK_LOSC:
1399 		return clock_get_frequency(sc->sc_node, "losc");
1400 	case V3S_CLK_HOSC:
1401 		return clock_get_frequency(sc->sc_node, "hosc");
1402 	case V3S_CLK_PLL_PERIPH0:
1403 		/* Not hardcoded, but recommended. */
1404 		return 600000000;
1405 	case V3S_CLK_APB2:
1406 		/* XXX Controlled by a MUX. */
1407 		return 24000000;
1408 	case V3S_CLK_AHB1:
1409 		reg = SXIREAD4(sc, CCU_AHB1_APB1_CFG_REG);
1410 		div = CCU_AHB1_CLK_DIV_RATIO(reg);
1411 		switch (reg & CCU_AHB1_CLK_SRC_SEL) {
1412 		case CCU_AHB1_CLK_SRC_SEL_LOSC:
1413 			parent = V3S_CLK_LOSC;
1414 			break;
1415 		case CCU_AHB1_CLK_SRC_SEL_OSC24M:
1416 			parent = V3S_CLK_HOSC;
1417 			break;
1418 		case CCU_AHB1_CLK_SRC_SEL_AXI:
1419 			parent = V3S_CLK_AXI;
1420 			break;
1421 		case CCU_AHB1_CLK_SRC_SEL_PERIPH0:
1422 			parent = V3S_CLK_PLL_PERIPH0;
1423 			div *= CCU_AHB1_PRE_DIV(reg);
1424 			break;
1425 		default:
1426 			return 0;
1427 		}
1428 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
1429 	case V3S_CLK_AHB2:
1430 		reg = SXIREAD4(sc, CCU_AHB2_CFG_REG);
1431 		switch (reg & CCU_AHB2_CLK_CFG) {
1432 		case 0:
1433 			parent = V3S_CLK_AHB1;
1434 			div = 1;
1435 			break;
1436 		case 1:
1437 			parent = V3S_CLK_PLL_PERIPH0;
1438 			div = 2;
1439 			break;
1440 		default:
1441 			return 0;
1442 		}
1443 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
1444 	}
1445 
1446 	printf("%s: 0x%08x\n", __func__, idx);
1447 	return 0;
1448 }
1449 
1450 uint32_t
1451 sxiccmu_nop_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
1452 {
1453 	printf("%s: 0x%08x\n", __func__, idx);
1454 	return 0;
1455 }
1456 
1457 int
1458 sxiccmu_ccu_set_frequency(void *cookie, uint32_t *cells, uint32_t freq)
1459 {
1460 	struct sxiccmu_softc *sc = cookie;
1461 	uint32_t idx = cells[0];
1462 
1463 	return sc->sc_set_frequency(sc, idx, freq);
1464 }
1465 
1466 int
1467 sxiccmu_a10_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1468 {
1469 	struct sxiccmu_clock clock;
1470 	uint32_t parent, parent_freq;
1471 	uint32_t reg;
1472 	int k, n;
1473 	int error;
1474 
1475 	switch (idx) {
1476 	case A10_CLK_PLL_CORE:
1477 		k = 1; n = 32;
1478 		while (k <= 4 && (24000000 * n * k) < freq)
1479 			k++;
1480 		while (n >= 1 && (24000000 * n * k) > freq)
1481 			n--;
1482 
1483 		reg = SXIREAD4(sc, A10_PLL1_CFG_REG);
1484 		reg &= ~A10_PLL1_OUT_EXT_DIVP_MASK;
1485 		reg &= ~A10_PLL1_FACTOR_N_MASK;
1486 		reg &= ~A10_PLL1_FACTOR_K_MASK;
1487 		reg &= ~A10_PLL1_FACTOR_M_MASK;
1488 		reg |= (n << A10_PLL1_FACTOR_N_SHIFT);
1489 		reg |= ((k - 1) << A10_PLL1_FACTOR_K_SHIFT);
1490 		SXIWRITE4(sc, A10_PLL1_CFG_REG, reg);
1491 
1492 		/* No need to wait PLL to lock? */
1493 
1494 		return 0;
1495 	case A10_CLK_CPU:
1496 		/* Switch to 24 MHz clock. */
1497 		reg = SXIREAD4(sc, A10_CPU_AHB_APB0_CFG_REG);
1498 		reg &= ~A10_CPU_CLK_SRC_SEL;
1499 		reg |= A10_CPU_CLK_SRC_SEL_OSC24M;
1500 		SXIWRITE4(sc, A10_CPU_AHB_APB0_CFG_REG, reg);
1501 
1502 		error = sxiccmu_a10_set_frequency(sc, A10_CLK_PLL_CORE, freq);
1503 
1504 		/* Switch back to PLL. */
1505 		reg = SXIREAD4(sc, A10_CPU_AHB_APB0_CFG_REG);
1506 		reg &= ~A10_CPU_CLK_SRC_SEL;
1507 		reg |= A10_CPU_CLK_SRC_SEL_PLL1;
1508 		SXIWRITE4(sc, A10_CPU_AHB_APB0_CFG_REG, reg);
1509 		return error;
1510 	case A10_CLK_MMC0:
1511 	case A10_CLK_MMC1:
1512 	case A10_CLK_MMC2:
1513 	case A10_CLK_MMC3:
1514 		clock.sc_iot = sc->sc_iot;
1515 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
1516 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
1517 		parent = A10_CLK_PLL_PERIPH;
1518 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
1519 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
1520 	}
1521 
1522 	printf("%s: 0x%08x\n", __func__, idx);
1523 	return -1;
1524 }
1525 
1526 int
1527 sxiccmu_a23_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1528 {
1529 	struct sxiccmu_clock clock;
1530 	uint32_t parent, parent_freq;
1531 
1532 	switch (idx) {
1533 	case A23_CLK_MMC0:
1534 	case A23_CLK_MMC1:
1535 	case A23_CLK_MMC2:
1536 		clock.sc_iot = sc->sc_iot;
1537 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
1538 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
1539 		parent = A23_CLK_PLL_PERIPH;
1540 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
1541 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
1542 	}
1543 
1544 	printf("%s: 0x%08x\n", __func__, idx);
1545 	return -1;
1546 }
1547 
1548 int
1549 sxiccmu_a64_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1550 {
1551 	struct sxiccmu_clock clock;
1552 	uint32_t parent, parent_freq;
1553 	uint32_t reg;
1554 	int k, n;
1555 	int error;
1556 
1557 	switch (idx) {
1558 	case A64_CLK_PLL_CPUX:
1559 		k = 1; n = 32;
1560 		while (k <= 4 && (24000000 * n * k) < freq)
1561 			k++;
1562 		while (n >= 1 && (24000000 * n * k) > freq)
1563 			n--;
1564 
1565 		reg = SXIREAD4(sc, A64_PLL_CPUX_CTRL_REG);
1566 		reg &= ~A64_PLL_CPUX_OUT_EXT_DIVP_MASK;
1567 		reg &= ~A64_PLL_CPUX_FACTOR_N_MASK;
1568 		reg &= ~A64_PLL_CPUX_FACTOR_K_MASK;
1569 		reg &= ~A64_PLL_CPUX_FACTOR_M_MASK;
1570 		reg |= ((n - 1) << A64_PLL_CPUX_FACTOR_N_SHIFT);
1571 		reg |= ((k - 1) << A64_PLL_CPUX_FACTOR_K_SHIFT);
1572 		SXIWRITE4(sc, A64_PLL_CPUX_CTRL_REG, reg);
1573 
1574 		/* Wait for PLL to lock. */
1575 		while ((SXIREAD4(sc, A64_PLL_CPUX_CTRL_REG) &
1576 		    A64_PLL_CPUX_LOCK) == 0) {
1577 			delay(200);
1578 		}
1579 
1580 		return 0;
1581 	case A64_CLK_CPUX:
1582 		/* Switch to 24 MHz clock. */
1583 		reg = SXIREAD4(sc, A64_CPUX_AXI_CFG_REG);
1584 		reg &= ~A64_CPUX_CLK_SRC_SEL;
1585 		reg |= A64_CPUX_CLK_SRC_SEL_OSC24M;
1586 		SXIWRITE4(sc, A64_CPUX_AXI_CFG_REG, reg);
1587 
1588 		error = sxiccmu_a64_set_frequency(sc, A64_CLK_PLL_CPUX, freq);
1589 
1590 		/* Switch back to PLL. */
1591 		reg = SXIREAD4(sc, A64_CPUX_AXI_CFG_REG);
1592 		reg &= ~A64_CPUX_CLK_SRC_SEL;
1593 		reg |= A64_CPUX_CLK_SRC_SEL_PLL_CPUX;
1594 		SXIWRITE4(sc, A64_CPUX_AXI_CFG_REG, reg);
1595 		return error;
1596 	case A64_CLK_MMC0:
1597 	case A64_CLK_MMC1:
1598 	case A64_CLK_MMC2:
1599 		clock.sc_iot = sc->sc_iot;
1600 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
1601 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
1602 		parent = A64_CLK_PLL_PERIPH0_2X;
1603 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
1604 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
1605 	}
1606 
1607 	printf("%s: 0x%08x\n", __func__, idx);
1608 	return -1;
1609 }
1610 
1611 int
1612 sxiccmu_a80_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1613 {
1614 	struct sxiccmu_clock clock;
1615 	uint32_t parent, parent_freq;
1616 
1617 	switch (idx) {
1618 	case A80_CLK_MMC0:
1619 	case A80_CLK_MMC1:
1620 	case A80_CLK_MMC2:
1621 		clock.sc_iot = sc->sc_iot;
1622 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
1623 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
1624 		parent = A80_CLK_PLL_PERIPH0;
1625 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
1626 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
1627 	}
1628 
1629 	printf("%s: 0x%08x\n", __func__, idx);
1630 	return -1;
1631 }
1632 
1633 int
1634 sxiccmu_h3_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1635 {
1636 	struct sxiccmu_clock clock;
1637 	uint32_t parent, parent_freq;
1638 	uint32_t reg, lock_time;
1639 	int k, n;
1640 	int error;
1641 
1642 	switch (idx) {
1643 	case H3_CLK_PLL_CPUX:
1644 		k = 1; n = 32;
1645 		while (k <= 4 && (24000000 * n * k) < freq)
1646 			k++;
1647 		while (n >= 1 && (24000000 * n * k) > freq)
1648 			n--;
1649 
1650 		/* Gate the PLL first */
1651 		reg = SXIREAD4(sc, H3_PLL_CPUX_CTRL_REG);
1652 		reg &= ~H3_PLL_CPUX_ENABLE;
1653 		SXIWRITE4(sc, H3_PLL_CPUX_CTRL_REG, reg);
1654 
1655 		/* Set factors and external divider. */
1656 		reg &= ~H3_PLL_CPUX_OUT_EXT_DIVP_MASK;
1657 		reg &= ~H3_PLL_CPUX_FACTOR_N_MASK;
1658 		reg &= ~H3_PLL_CPUX_FACTOR_K_MASK;
1659 		reg &= ~H3_PLL_CPUX_FACTOR_M_MASK;
1660 		reg |= ((n - 1) << H3_PLL_CPUX_FACTOR_N_SHIFT);
1661 		reg |= ((k - 1) << H3_PLL_CPUX_FACTOR_K_SHIFT);
1662 		SXIWRITE4(sc, H3_PLL_CPUX_CTRL_REG, reg);
1663 
1664 		/* Ungate the PLL */
1665 		reg |= H3_PLL_CPUX_ENABLE;
1666 		SXIWRITE4(sc, H3_PLL_CPUX_CTRL_REG, reg);
1667 
1668 		/* Wait for PLL to lock. (LOCK flag is unreliable) */
1669 		lock_time = SXIREAD4(sc, H3_PLL_STABLE_TIME_REG1);
1670 		delay(H3_PLL_STABLE_TIME_REG1_TIME(lock_time));
1671 
1672 		return 0;
1673 	case H3_CLK_CPUX:
1674 		/* Switch to 24 MHz clock. */
1675 		reg = SXIREAD4(sc, H3_CPUX_AXI_CFG_REG);
1676 		reg &= ~H3_CPUX_CLK_SRC_SEL;
1677 		reg |= H3_CPUX_CLK_SRC_SEL_OSC24M;
1678 		SXIWRITE4(sc, H3_CPUX_AXI_CFG_REG, reg);
1679 		/* Must wait at least 8 cycles of the current clock. */
1680 		delay(1);
1681 
1682 		error = sxiccmu_h3_set_frequency(sc, H3_CLK_PLL_CPUX, freq);
1683 
1684 		/* Switch back to PLL. */
1685 		reg = SXIREAD4(sc, H3_CPUX_AXI_CFG_REG);
1686 		reg &= ~H3_CPUX_CLK_SRC_SEL;
1687 		reg |= H3_CPUX_CLK_SRC_SEL_PLL_CPUX;
1688 		SXIWRITE4(sc, H3_CPUX_AXI_CFG_REG, reg);
1689 		/* Must wait at least 8 cycles of the current clock. */
1690 		delay(1);
1691 		return error;
1692 	case H3_CLK_MMC0:
1693 	case H3_CLK_MMC1:
1694 	case H3_CLK_MMC2:
1695 		clock.sc_iot = sc->sc_iot;
1696 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
1697 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
1698 		parent = H3_CLK_PLL_PERIPH0;
1699 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
1700 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
1701 	}
1702 
1703 	printf("%s: 0x%08x\n", __func__, idx);
1704 	return -1;
1705 }
1706 
1707 #define H6_SMHC0_CLK_REG		0x0830
1708 #define H6_SMHC1_CLK_REG		0x0834
1709 #define H6_SMHC2_CLK_REG		0x0838
1710 #define H6_SMHC_CLK_SRC_SEL			(0x3 << 24)
1711 #define H6_SMHC_CLK_SRC_SEL_OSC24M		(0x0 << 24)
1712 #define H6_SMHC_CLK_SRC_SEL_PLL_PERIPH0_2X	(0x1 << 24)
1713 #define H6_SMHC_FACTOR_N_MASK			(0x3 << 8)
1714 #define H6_SMHC_FACTOR_N_SHIFT			8
1715 #define H6_SMHC_FACTOR_M_MASK			(0xf << 0)
1716 #define H6_SMHC_FACTOR_M_SHIFT			0
1717 
1718 int
1719 sxiccmu_h6_mmc_set_frequency(struct sxiccmu_softc *sc, bus_size_t offset,
1720     uint32_t freq)
1721 {
1722 	uint32_t parent_freq;
1723 	uint32_t reg, m, n;
1724 	uint32_t clk_src;
1725 
1726 	switch (freq) {
1727 	case 400000:
1728 		n = 2, m = 15;
1729 		clk_src = H6_SMHC_CLK_SRC_SEL_OSC24M;
1730 		break;
1731 	case 20000000:
1732 	case 25000000:
1733 	case 26000000:
1734 	case 50000000:
1735 	case 52000000:
1736 		n = 0, m = 0;
1737 		clk_src = H6_SMHC_CLK_SRC_SEL_PLL_PERIPH0_2X;
1738 		parent_freq =
1739 		    sxiccmu_h6_get_frequency(sc, H6_CLK_PLL_PERIPH0_2X);
1740 		while ((parent_freq / (1 << n) / 16) > freq)
1741 			n++;
1742 		while ((parent_freq / (1 << n) / (m + 1)) > freq)
1743 			m++;
1744 		break;
1745 	default:
1746 		return -1;
1747 	}
1748 
1749 	reg = SXIREAD4(sc, offset);
1750 	reg &= ~H6_SMHC_CLK_SRC_SEL;
1751 	reg |= clk_src;
1752 	reg &= ~H6_SMHC_FACTOR_N_MASK;
1753 	reg |= n << H6_SMHC_FACTOR_N_SHIFT;
1754 	reg &= ~H6_SMHC_FACTOR_M_MASK;
1755 	reg |= m << H6_SMHC_FACTOR_M_SHIFT;
1756 	SXIWRITE4(sc, offset, reg);
1757 
1758 	return 0;
1759 }
1760 
1761 int
1762 sxiccmu_h6_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1763 {
1764 	switch (idx) {
1765 	case H6_CLK_MMC0:
1766 		return sxiccmu_h6_mmc_set_frequency(sc, H6_SMHC0_CLK_REG, freq);
1767 	case H6_CLK_MMC1:
1768 		return sxiccmu_h6_mmc_set_frequency(sc, H6_SMHC1_CLK_REG, freq);
1769 	case H6_CLK_MMC2:
1770 		return sxiccmu_h6_mmc_set_frequency(sc, H6_SMHC2_CLK_REG, freq);
1771 	}
1772 
1773 	printf("%s: 0x%08x\n", __func__, idx);
1774 	return -1;
1775 }
1776 
1777 int
1778 sxiccmu_r40_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1779 {
1780 	struct sxiccmu_clock clock;
1781 	uint32_t parent, parent_freq;
1782 
1783 	switch (idx) {
1784 	case R40_CLK_MMC0:
1785 	case R40_CLK_MMC1:
1786 	case R40_CLK_MMC2:
1787 	case R40_CLK_MMC3:
1788 		clock.sc_iot = sc->sc_iot;
1789 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
1790 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
1791 		parent = R40_CLK_PLL_PERIPH0_2X;
1792 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
1793 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
1794 	}
1795 
1796 	printf("%s: 0x%08x\n", __func__, idx);
1797 	return -1;
1798 }
1799 
1800 int
1801 sxiccmu_v3s_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1802 {
1803 	struct sxiccmu_clock clock;
1804 	uint32_t parent, parent_freq;
1805 
1806 	switch (idx) {
1807 	case V3S_CLK_MMC0:
1808 	case V3S_CLK_MMC1:
1809 	case V3S_CLK_MMC2:
1810 		clock.sc_iot = sc->sc_iot;
1811 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
1812 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
1813 		parent = V3S_CLK_PLL_PERIPH0;
1814 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
1815 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
1816 	}
1817 
1818 	printf("%s: 0x%08x\n", __func__, idx);
1819 	return -1;
1820 }
1821 
1822 int
1823 sxiccmu_nop_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1824 {
1825 	printf("%s: 0x%08x\n", __func__, idx);
1826 	return -1;
1827 }
1828 
1829 void
1830 sxiccmu_ccu_enable(void *cookie, uint32_t *cells, int on)
1831 {
1832 	struct sxiccmu_softc *sc = cookie;
1833 	uint32_t idx = cells[0];
1834 	int reg, bit;
1835 
1836 	clock_enable_all(sc->sc_node);
1837 
1838 	if (idx >= sc->sc_ngates ||
1839 	    (sc->sc_gates[idx].reg == 0 && sc->sc_gates[idx].bit == 0)) {
1840 		printf("%s: 0x%08x\n", __func__, cells[0]);
1841 		return;
1842 	}
1843 
1844 	/* If the clock can't be gated, simply return. */
1845 	if (sc->sc_gates[idx].reg == 0xffff && sc->sc_gates[idx].bit == 0xff)
1846 		return;
1847 
1848 	reg = sc->sc_gates[idx].reg;
1849 	bit = sc->sc_gates[idx].bit;
1850 
1851 	if (on)
1852 		SXISET4(sc, reg, (1U << bit));
1853 	else
1854 		SXICLR4(sc, reg, (1U << bit));
1855 }
1856 
1857 void
1858 sxiccmu_ccu_reset(void *cookie, uint32_t *cells, int assert)
1859 {
1860 	struct sxiccmu_softc *sc = cookie;
1861 	uint32_t idx = cells[0];
1862 	int reg, bit;
1863 
1864 	reset_deassert_all(sc->sc_node);
1865 
1866 	if (idx >= sc->sc_nresets ||
1867 	    (sc->sc_resets[idx].reg == 0 && sc->sc_gates[idx].bit == 0)) {
1868 		printf("%s: 0x%08x\n", __func__, cells[0]);
1869 		return;
1870 	}
1871 
1872 	reg = sc->sc_resets[idx].reg;
1873 	bit = sc->sc_resets[idx].bit;
1874 
1875 	if (assert)
1876 		SXICLR4(sc, reg, (1U << bit));
1877 	else
1878 		SXISET4(sc, reg, (1U << bit));
1879 }
1880