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