xref: /openbsd-src/sys/dev/fdt/sxiccmu.c (revision 99fd087599a8791921855f21bd7e36130f39aadc)
1 /*	$OpenBSD: sxiccmu.c,v 1.26 2019/09/21 15:01:26 kettenis Exp $	*/
2 /*
3  * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
4  * Copyright (c) 2013 Artturi Alm
5  * Copyright (c) 2016,2017 Mark Kettenis <kettenis@openbsd.org>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/param.h>
21 #include <sys/systm.h>
22 #include <sys/kernel.h>
23 #include <sys/malloc.h>
24 #include <sys/time.h>
25 #include <sys/device.h>
26 
27 #include <machine/bus.h>
28 #include <machine/fdt.h>
29 #include <machine/intr.h>
30 
31 #include <dev/fdt/sunxireg.h>
32 
33 #include <dev/ofw/openfirm.h>
34 #include <dev/ofw/ofw_clock.h>
35 #include <dev/ofw/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 uint32_t
1120 sxiccmu_a80_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
1121 {
1122 	switch (idx) {
1123 	case A80_CLK_PLL_PERIPH0:
1124 		/* Not hardcoded, but recommended. */
1125 		return 960000000;
1126 	case A80_CLK_APB1:
1127 		/* XXX Controlled by a MUX. */
1128 		return 24000000;
1129 	}
1130 
1131 	printf("%s: 0x%08x\n", __func__, idx);
1132 	return 0;
1133 }
1134 
1135 /* Allwinner H3/H5 */
1136 #define H3_PLL_CPUX_CTRL_REG		0x0000
1137 #define H3_PLL_CPUX_LOCK		(1 << 28)
1138 #define H3_PLL_CPUX_OUT_EXT_DIVP(x)	(((x) >> 16) & 0x3)
1139 #define H3_PLL_CPUX_OUT_EXT_DIVP_MASK	(0x3 << 16)
1140 #define H3_PLL_CPUX_OUT_EXT_DIVP_SHIFT	16
1141 #define H3_PLL_CPUX_FACTOR_N(x)		(((x) >> 8) & 0x1f)
1142 #define H3_PLL_CPUX_FACTOR_N_MASK	(0x1f << 8)
1143 #define H3_PLL_CPUX_FACTOR_N_SHIFT	8
1144 #define H3_PLL_CPUX_FACTOR_K(x)		(((x) >> 4) & 0x3)
1145 #define H3_PLL_CPUX_FACTOR_K_MASK	(0x3 << 4)
1146 #define H3_PLL_CPUX_FACTOR_K_SHIFT	4
1147 #define H3_PLL_CPUX_FACTOR_M(x)		(((x) >> 0) & 0x3)
1148 #define H3_PLL_CPUX_FACTOR_M_MASK	(0x3 << 0)
1149 #define H3_PLL_CPUX_FACTOR_M_SHIFT	0
1150 #define H3_CPUX_AXI_CFG_REG		0x0050
1151 #define H3_CPUX_CLK_SRC_SEL		(0x3 << 16)
1152 #define H3_CPUX_CLK_SRC_SEL_LOSC	(0x0 << 16)
1153 #define H3_CPUX_CLK_SRC_SEL_OSC24M	(0x1 << 16)
1154 #define H3_CPUX_CLK_SRC_SEL_PLL_CPUX	(0x2 << 16)
1155 
1156 uint32_t
1157 sxiccmu_h3_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
1158 {
1159 	uint32_t parent;
1160 	uint32_t reg, div;
1161 	uint32_t k, m, n, p;
1162 
1163 	switch (idx) {
1164 	case H3_CLK_LOSC:
1165 		return clock_get_frequency(sc->sc_node, "losc");
1166 	case H3_CLK_HOSC:
1167 		return clock_get_frequency(sc->sc_node, "hosc");
1168 	case H3_CLK_PLL_CPUX:
1169 		reg = SXIREAD4(sc, H3_PLL_CPUX_CTRL_REG);
1170 		k = H3_PLL_CPUX_FACTOR_K(reg) + 1;
1171 		m = H3_PLL_CPUX_FACTOR_M(reg) + 1;
1172 		n = H3_PLL_CPUX_FACTOR_N(reg) + 1;
1173 		p = 1 << H3_PLL_CPUX_OUT_EXT_DIVP(reg);
1174 		return (24000000 * n * k) / (m * p);
1175 	case H3_CLK_PLL_PERIPH0:
1176 		/* Not hardcoded, but recommended. */
1177 		return 600000000;
1178 	case H3_CLK_CPUX:
1179 		reg = SXIREAD4(sc, H3_CPUX_AXI_CFG_REG);
1180 		switch (reg & H3_CPUX_CLK_SRC_SEL) {
1181 		case H3_CPUX_CLK_SRC_SEL_LOSC:
1182 			parent = H3_CLK_LOSC;
1183 			break;
1184 		case H3_CPUX_CLK_SRC_SEL_OSC24M:
1185 			parent = H3_CLK_HOSC;
1186 			break;
1187 		case H3_CPUX_CLK_SRC_SEL_PLL_CPUX:
1188 			parent = H3_CLK_PLL_CPUX;
1189 			break;
1190 		default:
1191 			return 0;
1192 		}
1193 		return sxiccmu_ccu_get_frequency(sc, &parent);
1194 	case H3_CLK_APB2:
1195 		/* XXX Controlled by a MUX. */
1196 		return 24000000;
1197 	case H3_CLK_AHB1:
1198 		reg = SXIREAD4(sc, CCU_AHB1_APB1_CFG_REG);
1199 		div = CCU_AHB1_CLK_DIV_RATIO(reg);
1200 		switch (reg & CCU_AHB1_CLK_SRC_SEL) {
1201 		case CCU_AHB1_CLK_SRC_SEL_LOSC:
1202 			parent = H3_CLK_LOSC;
1203 			break;
1204 		case CCU_AHB1_CLK_SRC_SEL_OSC24M:
1205 			parent = H3_CLK_HOSC;
1206 			break;
1207 		case CCU_AHB1_CLK_SRC_SEL_AXI:
1208 			parent = H3_CLK_AXI;
1209 			break;
1210 		case CCU_AHB1_CLK_SRC_SEL_PERIPH0:
1211 			parent = H3_CLK_PLL_PERIPH0;
1212 			div *= CCU_AHB1_PRE_DIV(reg);
1213 			break;
1214 		default:
1215 			return 0;
1216 		}
1217 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
1218 	case H3_CLK_AHB2:
1219 		reg = SXIREAD4(sc, CCU_AHB2_CFG_REG);
1220 		switch (reg & CCU_AHB2_CLK_CFG) {
1221 		case 0:
1222 			parent = H3_CLK_AHB1;
1223 			div = 1;
1224 			break;
1225 		case 1:
1226 			parent = H3_CLK_PLL_PERIPH0;
1227 			div = 2;
1228 			break;
1229 		default:
1230 			return 0;
1231 		}
1232 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
1233 	}
1234 
1235 	printf("%s: 0x%08x\n", __func__, idx);
1236 	return 0;
1237 }
1238 
1239 #define H3_AHB0_CLK_REG			0x0000
1240 #define H3_AHB0_CLK_SRC_SEL		(0x3 << 16)
1241 #define H3_AHB0_CLK_SRC_SEL_OSC32K	(0x0 << 16)
1242 #define H3_AHB0_CLK_SRC_SEL_OSC24M	(0x1 << 16)
1243 #define H3_AHB0_CLK_SRC_SEL_PLL_PERIPH0	(0x2 << 16)
1244 #define H3_AHB0_CLK_SRC_SEL_IOSC	(0x3 << 16)
1245 #define H3_AHB0_CLK_PRE_DIV(x)		((((x) >> 8) & 0x1f) + 1)
1246 #define H3_AHB0_CLK_RATIO(x)		(1 << (((x) >> 4) & 3))
1247 #define H3_APB0_CFG_REG			0x000c
1248 #define H3_APB0_CLK_RATIO(x)		(1 << ((x) & 1))
1249 
1250 uint32_t
1251 sxiccmu_h3_r_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
1252 {
1253 	uint32_t parent;
1254 	uint32_t reg, div;
1255 	uint32_t freq;
1256 
1257 	switch (idx) {
1258 	case H3_R_CLK_AHB0:
1259 		reg = SXIREAD4(sc, H3_AHB0_CLK_REG);
1260 		switch (reg & H3_AHB0_CLK_SRC_SEL) {
1261 		case H3_AHB0_CLK_SRC_SEL_OSC32K:
1262 			freq = clock_get_frequency(sc->sc_node, "losc");
1263 			break;
1264 		case H3_AHB0_CLK_SRC_SEL_OSC24M:
1265 			freq = clock_get_frequency(sc->sc_node, "hosc");
1266 			break;
1267 		case H3_AHB0_CLK_SRC_SEL_PLL_PERIPH0:
1268 			freq = clock_get_frequency(sc->sc_node, "pll-periph");
1269 			break;
1270 		case H3_AHB0_CLK_SRC_SEL_IOSC:
1271 			freq = clock_get_frequency(sc->sc_node, "iosc");
1272 			break;
1273 		}
1274 		div = H3_AHB0_CLK_PRE_DIV(reg) * H3_AHB0_CLK_RATIO(reg);
1275 		return freq / div;
1276 	case H3_R_CLK_APB0:
1277 		reg = SXIREAD4(sc, H3_APB0_CFG_REG);
1278 		div = H3_APB0_CLK_RATIO(reg);
1279 		parent = H3_R_CLK_AHB0;
1280 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
1281 	}
1282 
1283 	printf("%s: 0x%08x\n", __func__, idx);
1284 	return 0;
1285 }
1286 
1287 uint32_t
1288 sxiccmu_h6_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
1289 {
1290 	switch (idx) {
1291 	case H6_CLK_PLL_PERIPH0:
1292 		/* Not hardcoded, but recommended. */
1293 		return 600000000;
1294 	case H6_CLK_PLL_PERIPH0_2X:
1295 		return sxiccmu_h6_get_frequency(sc, H6_CLK_PLL_PERIPH0) * 2;
1296 	case H6_CLK_APB2:
1297 		/* XXX Controlled by a MUX. */
1298 		return 24000000;
1299 		break;
1300 	}
1301 
1302 	printf("%s: 0x%08x\n", __func__, idx);
1303 	return 0;
1304 }
1305 
1306 uint32_t
1307 sxiccmu_h6_r_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
1308 {
1309 	switch (idx) {
1310 	case H6_R_CLK_APB2:
1311 		/* XXX Controlled by a MUX. */
1312 		return 24000000;
1313 		break;
1314 	}
1315 
1316 	printf("%s: 0x%08x\n", __func__, idx);
1317 	return 0;
1318 }
1319 
1320 uint32_t
1321 sxiccmu_r40_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
1322 {
1323 	uint32_t parent;
1324 	uint32_t reg, div;
1325 
1326 	switch (idx) {
1327 	case R40_CLK_LOSC:
1328 		return clock_get_frequency(sc->sc_node, "losc");
1329 	case R40_CLK_HOSC:
1330 		return clock_get_frequency(sc->sc_node, "hosc");
1331 	case R40_CLK_PLL_PERIPH0:
1332 		/* Not hardcoded, but recommended. */
1333 		return 600000000;
1334 	case R40_CLK_PLL_PERIPH0_2X:
1335 		return sxiccmu_r40_get_frequency(sc, R40_CLK_PLL_PERIPH0) * 2;
1336 	case R40_CLK_AHB1:
1337 		reg = SXIREAD4(sc, CCU_AHB1_APB1_CFG_REG);
1338 		div = CCU_AHB1_CLK_DIV_RATIO(reg);
1339 		switch (reg & CCU_AHB1_CLK_SRC_SEL) {
1340 		case CCU_AHB1_CLK_SRC_SEL_LOSC:
1341 			parent = R40_CLK_LOSC;
1342 			break;
1343 		case CCU_AHB1_CLK_SRC_SEL_OSC24M:
1344 			parent = R40_CLK_HOSC;
1345 			break;
1346 		case CCU_AHB1_CLK_SRC_SEL_AXI:
1347 			parent = R40_CLK_AXI;
1348 			break;
1349 		case CCU_AHB1_CLK_SRC_SEL_PERIPH0:
1350 			parent = R40_CLK_PLL_PERIPH0;
1351 			div *= CCU_AHB1_PRE_DIV(reg);
1352 			break;
1353 		}
1354 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
1355 	case R40_CLK_APB2:
1356 		/* XXX Controlled by a MUX. */
1357 		return 24000000;
1358 	}
1359 
1360 	printf("%s: 0x%08x\n", __func__, idx);
1361 	return 0;
1362 }
1363 
1364 uint32_t
1365 sxiccmu_v3s_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
1366 {
1367 	uint32_t parent;
1368 	uint32_t reg, div;
1369 
1370 	switch (idx) {
1371 	case V3S_CLK_LOSC:
1372 		return clock_get_frequency(sc->sc_node, "losc");
1373 	case V3S_CLK_HOSC:
1374 		return clock_get_frequency(sc->sc_node, "hosc");
1375 	case V3S_CLK_PLL_PERIPH0:
1376 		/* Not hardcoded, but recommended. */
1377 		return 600000000;
1378 	case V3S_CLK_APB2:
1379 		/* XXX Controlled by a MUX. */
1380 		return 24000000;
1381 	case V3S_CLK_AHB1:
1382 		reg = SXIREAD4(sc, CCU_AHB1_APB1_CFG_REG);
1383 		div = CCU_AHB1_CLK_DIV_RATIO(reg);
1384 		switch (reg & CCU_AHB1_CLK_SRC_SEL) {
1385 		case CCU_AHB1_CLK_SRC_SEL_LOSC:
1386 			parent = V3S_CLK_LOSC;
1387 			break;
1388 		case CCU_AHB1_CLK_SRC_SEL_OSC24M:
1389 			parent = V3S_CLK_HOSC;
1390 			break;
1391 		case CCU_AHB1_CLK_SRC_SEL_AXI:
1392 			parent = V3S_CLK_AXI;
1393 			break;
1394 		case CCU_AHB1_CLK_SRC_SEL_PERIPH0:
1395 			parent = V3S_CLK_PLL_PERIPH0;
1396 			div *= CCU_AHB1_PRE_DIV(reg);
1397 			break;
1398 		default:
1399 			return 0;
1400 		}
1401 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
1402 	case V3S_CLK_AHB2:
1403 		reg = SXIREAD4(sc, CCU_AHB2_CFG_REG);
1404 		switch (reg & CCU_AHB2_CLK_CFG) {
1405 		case 0:
1406 			parent = V3S_CLK_AHB1;
1407 			div = 1;
1408 			break;
1409 		case 1:
1410 			parent = V3S_CLK_PLL_PERIPH0;
1411 			div = 2;
1412 			break;
1413 		default:
1414 			return 0;
1415 		}
1416 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
1417 	}
1418 
1419 	printf("%s: 0x%08x\n", __func__, idx);
1420 	return 0;
1421 }
1422 
1423 uint32_t
1424 sxiccmu_nop_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
1425 {
1426 	printf("%s: 0x%08x\n", __func__, idx);
1427 	return 0;
1428 }
1429 
1430 int
1431 sxiccmu_ccu_set_frequency(void *cookie, uint32_t *cells, uint32_t freq)
1432 {
1433 	struct sxiccmu_softc *sc = cookie;
1434 	uint32_t idx = cells[0];
1435 
1436 	return sc->sc_set_frequency(sc, idx, freq);
1437 }
1438 
1439 int
1440 sxiccmu_a10_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1441 {
1442 	struct sxiccmu_clock clock;
1443 	uint32_t parent, parent_freq;
1444 	uint32_t reg;
1445 	int k, n;
1446 	int error;
1447 
1448 	switch (idx) {
1449 	case A10_CLK_PLL_CORE:
1450 		k = 1; n = 32;
1451 		while (k <= 4 && (24000000 * n * k) < freq)
1452 			k++;
1453 		while (n >= 1 && (24000000 * n * k) > freq)
1454 			n--;
1455 
1456 		reg = SXIREAD4(sc, A10_PLL1_CFG_REG);
1457 		reg &= ~A10_PLL1_OUT_EXT_DIVP_MASK;
1458 		reg &= ~A10_PLL1_FACTOR_N_MASK;
1459 		reg &= ~A10_PLL1_FACTOR_K_MASK;
1460 		reg &= ~A10_PLL1_FACTOR_M_MASK;
1461 		reg |= (n << A10_PLL1_FACTOR_N_SHIFT);
1462 		reg |= ((k - 1) << A10_PLL1_FACTOR_K_SHIFT);
1463 		SXIWRITE4(sc, A10_PLL1_CFG_REG, reg);
1464 
1465 		/* No need to wait PLL to lock? */
1466 
1467 		return 0;
1468 	case A10_CLK_CPU:
1469 		/* Switch to 24 MHz clock. */
1470 		reg = SXIREAD4(sc, A10_CPU_AHB_APB0_CFG_REG);
1471 		reg &= ~A10_CPU_CLK_SRC_SEL;
1472 		reg |= A10_CPU_CLK_SRC_SEL_OSC24M;
1473 		SXIWRITE4(sc, A10_CPU_AHB_APB0_CFG_REG, reg);
1474 
1475 		error = sxiccmu_a10_set_frequency(sc, A10_CLK_PLL_CORE, freq);
1476 
1477 		/* Switch back to PLL. */
1478 		reg = SXIREAD4(sc, A10_CPU_AHB_APB0_CFG_REG);
1479 		reg &= ~A10_CPU_CLK_SRC_SEL;
1480 		reg |= A10_CPU_CLK_SRC_SEL_PLL1;
1481 		SXIWRITE4(sc, A10_CPU_AHB_APB0_CFG_REG, reg);
1482 		return error;
1483 	case A10_CLK_MMC0:
1484 	case A10_CLK_MMC1:
1485 	case A10_CLK_MMC2:
1486 	case A10_CLK_MMC3:
1487 		clock.sc_iot = sc->sc_iot;
1488 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
1489 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
1490 		parent = A10_CLK_PLL_PERIPH;
1491 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
1492 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
1493 	}
1494 
1495 	printf("%s: 0x%08x\n", __func__, idx);
1496 	return -1;
1497 }
1498 
1499 int
1500 sxiccmu_a23_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1501 {
1502 	struct sxiccmu_clock clock;
1503 	uint32_t parent, parent_freq;
1504 
1505 	switch (idx) {
1506 	case A23_CLK_MMC0:
1507 	case A23_CLK_MMC1:
1508 	case A23_CLK_MMC2:
1509 		clock.sc_iot = sc->sc_iot;
1510 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
1511 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
1512 		parent = A23_CLK_PLL_PERIPH;
1513 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
1514 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
1515 	}
1516 
1517 	printf("%s: 0x%08x\n", __func__, idx);
1518 	return -1;
1519 }
1520 
1521 int
1522 sxiccmu_a64_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1523 {
1524 	struct sxiccmu_clock clock;
1525 	uint32_t parent, parent_freq;
1526 	uint32_t reg;
1527 	int k, n;
1528 	int error;
1529 
1530 	switch (idx) {
1531 	case A64_CLK_PLL_CPUX:
1532 		k = 1; n = 32;
1533 		while (k <= 4 && (24000000 * n * k) < freq)
1534 			k++;
1535 		while (n >= 1 && (24000000 * n * k) > freq)
1536 			n--;
1537 
1538 		reg = SXIREAD4(sc, A64_PLL_CPUX_CTRL_REG);
1539 		reg &= ~A64_PLL_CPUX_OUT_EXT_DIVP_MASK;
1540 		reg &= ~A64_PLL_CPUX_FACTOR_N_MASK;
1541 		reg &= ~A64_PLL_CPUX_FACTOR_K_MASK;
1542 		reg &= ~A64_PLL_CPUX_FACTOR_M_MASK;
1543 		reg |= ((n - 1) << A64_PLL_CPUX_FACTOR_N_SHIFT);
1544 		reg |= ((k - 1) << A64_PLL_CPUX_FACTOR_K_SHIFT);
1545 		SXIWRITE4(sc, A64_PLL_CPUX_CTRL_REG, reg);
1546 
1547 		/* Wait for PLL to lock. */
1548 		while ((SXIREAD4(sc, A64_PLL_CPUX_CTRL_REG) &
1549 		    A64_PLL_CPUX_LOCK) == 0) {
1550 			delay(200);
1551 		}
1552 
1553 		return 0;
1554 	case A64_CLK_CPUX:
1555 		/* Switch to 24 MHz clock. */
1556 		reg = SXIREAD4(sc, A64_CPUX_AXI_CFG_REG);
1557 		reg &= ~A64_CPUX_CLK_SRC_SEL;
1558 		reg |= A64_CPUX_CLK_SRC_SEL_OSC24M;
1559 		SXIWRITE4(sc, A64_CPUX_AXI_CFG_REG, reg);
1560 
1561 		error = sxiccmu_a64_set_frequency(sc, A64_CLK_PLL_CPUX, freq);
1562 
1563 		/* Switch back to PLL. */
1564 		reg = SXIREAD4(sc, A64_CPUX_AXI_CFG_REG);
1565 		reg &= ~A64_CPUX_CLK_SRC_SEL;
1566 		reg |= A64_CPUX_CLK_SRC_SEL_PLL_CPUX;
1567 		SXIWRITE4(sc, A64_CPUX_AXI_CFG_REG, reg);
1568 		return error;
1569 	case A64_CLK_MMC0:
1570 	case A64_CLK_MMC1:
1571 	case A64_CLK_MMC2:
1572 		clock.sc_iot = sc->sc_iot;
1573 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
1574 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
1575 		parent = A64_CLK_PLL_PERIPH0_2X;
1576 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
1577 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
1578 	}
1579 
1580 	printf("%s: 0x%08x\n", __func__, idx);
1581 	return -1;
1582 }
1583 
1584 int
1585 sxiccmu_a80_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1586 {
1587 	struct sxiccmu_clock clock;
1588 	uint32_t parent, parent_freq;
1589 
1590 	switch (idx) {
1591 	case A80_CLK_MMC0:
1592 	case A80_CLK_MMC1:
1593 	case A80_CLK_MMC2:
1594 		clock.sc_iot = sc->sc_iot;
1595 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
1596 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
1597 		parent = A80_CLK_PLL_PERIPH0;
1598 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
1599 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
1600 	}
1601 
1602 	printf("%s: 0x%08x\n", __func__, idx);
1603 	return -1;
1604 }
1605 
1606 int
1607 sxiccmu_h3_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1608 {
1609 	struct sxiccmu_clock clock;
1610 	uint32_t parent, parent_freq;
1611 	uint32_t reg;
1612 	int k, n;
1613 	int error;
1614 
1615 	switch (idx) {
1616 	case H3_CLK_PLL_CPUX:
1617 		k = 1; n = 32;
1618 		while (k <= 4 && (24000000 * n * k) < freq)
1619 			k++;
1620 		while (n >= 1 && (24000000 * n * k) > freq)
1621 			n--;
1622 
1623 		reg = SXIREAD4(sc, H3_PLL_CPUX_CTRL_REG);
1624 		reg &= ~H3_PLL_CPUX_OUT_EXT_DIVP_MASK;
1625 		reg &= ~H3_PLL_CPUX_FACTOR_N_MASK;
1626 		reg &= ~H3_PLL_CPUX_FACTOR_K_MASK;
1627 		reg &= ~H3_PLL_CPUX_FACTOR_M_MASK;
1628 		reg |= ((n - 1) << H3_PLL_CPUX_FACTOR_N_SHIFT);
1629 		reg |= ((k - 1) << H3_PLL_CPUX_FACTOR_K_SHIFT);
1630 		SXIWRITE4(sc, H3_PLL_CPUX_CTRL_REG, reg);
1631 
1632 		/* Wait for PLL to lock. */
1633 		while ((SXIREAD4(sc, H3_PLL_CPUX_CTRL_REG) &
1634 		    H3_PLL_CPUX_LOCK) == 0)
1635 			delay(1);
1636 
1637 		return 0;
1638 	case H3_CLK_CPUX:
1639 		/* Switch to 24 MHz clock. */
1640 		reg = SXIREAD4(sc, H3_CPUX_AXI_CFG_REG);
1641 		reg &= ~H3_CPUX_CLK_SRC_SEL;
1642 		reg |= H3_CPUX_CLK_SRC_SEL_OSC24M;
1643 		SXIWRITE4(sc, H3_CPUX_AXI_CFG_REG, reg);
1644 
1645 		error = sxiccmu_h3_set_frequency(sc, H3_CLK_PLL_CPUX, freq);
1646 
1647 		/* Switch back to PLL. */
1648 		reg = SXIREAD4(sc, H3_CPUX_AXI_CFG_REG);
1649 		reg &= ~H3_CPUX_CLK_SRC_SEL;
1650 		reg |= H3_CPUX_CLK_SRC_SEL_PLL_CPUX;
1651 		SXIWRITE4(sc, H3_CPUX_AXI_CFG_REG, reg);
1652 		return error;
1653 	case H3_CLK_MMC0:
1654 	case H3_CLK_MMC1:
1655 	case H3_CLK_MMC2:
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 = H3_CLK_PLL_PERIPH0;
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 #define H6_SMHC0_CLK_REG		0x0830
1669 #define H6_SMHC1_CLK_REG		0x0834
1670 #define H6_SMHC2_CLK_REG		0x0838
1671 #define H6_SMHC_CLK_SRC_SEL			(0x3 << 24)
1672 #define H6_SMHC_CLK_SRC_SEL_OSC24M		(0x0 << 24)
1673 #define H6_SMHC_CLK_SRC_SEL_PLL_PERIPH0_2X	(0x1 << 24)
1674 #define H6_SMHC_FACTOR_N_MASK			(0x3 << 8)
1675 #define H6_SMHC_FACTOR_N_SHIFT			8
1676 #define H6_SMHC_FACTOR_M_MASK			(0xf << 0)
1677 #define H6_SMHC_FACTOR_M_SHIFT			0
1678 
1679 int
1680 sxiccmu_h6_mmc_set_frequency(struct sxiccmu_softc *sc, bus_size_t offset,
1681     uint32_t freq)
1682 {
1683 	uint32_t parent_freq;
1684 	uint32_t reg, m, n;
1685 	uint32_t clk_src;
1686 
1687 	switch (freq) {
1688 	case 400000:
1689 		n = 2, m = 15;
1690 		clk_src = H6_SMHC_CLK_SRC_SEL_OSC24M;
1691 		break;
1692 	case 20000000:
1693 	case 25000000:
1694 	case 26000000:
1695 	case 50000000:
1696 	case 52000000:
1697 		n = 0, m = 0;
1698 		clk_src = H6_SMHC_CLK_SRC_SEL_PLL_PERIPH0_2X;
1699 		parent_freq =
1700 		    sxiccmu_h6_get_frequency(sc, H6_CLK_PLL_PERIPH0_2X);
1701 		while ((parent_freq / (1 << n) / 16) > freq)
1702 			n++;
1703 		while ((parent_freq / (1 << n) / (m + 1)) > freq)
1704 			m++;
1705 		break;
1706 	default:
1707 		return -1;
1708 	}
1709 
1710 	reg = SXIREAD4(sc, offset);
1711 	reg &= ~H6_SMHC_CLK_SRC_SEL;
1712 	reg |= clk_src;
1713 	reg &= ~H6_SMHC_FACTOR_N_MASK;
1714 	reg |= n << H6_SMHC_FACTOR_N_SHIFT;
1715 	reg &= ~H6_SMHC_FACTOR_M_MASK;
1716 	reg |= m << H6_SMHC_FACTOR_M_SHIFT;
1717 	SXIWRITE4(sc, offset, reg);
1718 
1719 	return 0;
1720 }
1721 
1722 int
1723 sxiccmu_h6_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1724 {
1725 	switch (idx) {
1726 	case H6_CLK_MMC0:
1727 		return sxiccmu_h6_mmc_set_frequency(sc, H6_SMHC0_CLK_REG, freq);
1728 	case H6_CLK_MMC1:
1729 		return sxiccmu_h6_mmc_set_frequency(sc, H6_SMHC1_CLK_REG, freq);
1730 	case H6_CLK_MMC2:
1731 		return sxiccmu_h6_mmc_set_frequency(sc, H6_SMHC2_CLK_REG, freq);
1732 	}
1733 
1734 	printf("%s: 0x%08x\n", __func__, idx);
1735 	return -1;
1736 }
1737 
1738 int
1739 sxiccmu_r40_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1740 {
1741 	struct sxiccmu_clock clock;
1742 	uint32_t parent, parent_freq;
1743 
1744 	switch (idx) {
1745 	case R40_CLK_MMC0:
1746 	case R40_CLK_MMC1:
1747 	case R40_CLK_MMC2:
1748 	case R40_CLK_MMC3:
1749 		clock.sc_iot = sc->sc_iot;
1750 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
1751 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
1752 		parent = R40_CLK_PLL_PERIPH0_2X;
1753 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
1754 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
1755 	}
1756 
1757 	printf("%s: 0x%08x\n", __func__, idx);
1758 	return -1;
1759 }
1760 
1761 int
1762 sxiccmu_v3s_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1763 {
1764 	struct sxiccmu_clock clock;
1765 	uint32_t parent, parent_freq;
1766 
1767 	switch (idx) {
1768 	case V3S_CLK_MMC0:
1769 	case V3S_CLK_MMC1:
1770 	case V3S_CLK_MMC2:
1771 		clock.sc_iot = sc->sc_iot;
1772 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
1773 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
1774 		parent = V3S_CLK_PLL_PERIPH0;
1775 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
1776 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
1777 	}
1778 
1779 	printf("%s: 0x%08x\n", __func__, idx);
1780 	return -1;
1781 }
1782 
1783 int
1784 sxiccmu_nop_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1785 {
1786 	printf("%s: 0x%08x\n", __func__, idx);
1787 	return -1;
1788 }
1789 
1790 void
1791 sxiccmu_ccu_enable(void *cookie, uint32_t *cells, int on)
1792 {
1793 	struct sxiccmu_softc *sc = cookie;
1794 	uint32_t idx = cells[0];
1795 	int reg, bit;
1796 
1797 	clock_enable_all(sc->sc_node);
1798 
1799 	if (idx >= sc->sc_ngates ||
1800 	    (sc->sc_gates[idx].reg == 0 && sc->sc_gates[idx].bit == 0)) {
1801 		printf("%s: 0x%08x\n", __func__, cells[0]);
1802 		return;
1803 	}
1804 
1805 	/* If the clock can't be gated, simply return. */
1806 	if (sc->sc_gates[idx].reg == 0xffff && sc->sc_gates[idx].bit == 0xff)
1807 		return;
1808 
1809 	reg = sc->sc_gates[idx].reg;
1810 	bit = sc->sc_gates[idx].bit;
1811 
1812 	if (on)
1813 		SXISET4(sc, reg, (1U << bit));
1814 	else
1815 		SXICLR4(sc, reg, (1U << bit));
1816 }
1817 
1818 void
1819 sxiccmu_ccu_reset(void *cookie, uint32_t *cells, int assert)
1820 {
1821 	struct sxiccmu_softc *sc = cookie;
1822 	uint32_t idx = cells[0];
1823 	int reg, bit;
1824 
1825 	reset_deassert_all(sc->sc_node);
1826 
1827 	if (idx >= sc->sc_nresets ||
1828 	    (sc->sc_resets[idx].reg == 0 && sc->sc_gates[idx].bit == 0)) {
1829 		printf("%s: 0x%08x\n", __func__, cells[0]);
1830 		return;
1831 	}
1832 
1833 	reg = sc->sc_resets[idx].reg;
1834 	bit = sc->sc_resets[idx].bit;
1835 
1836 	if (assert)
1837 		SXICLR4(sc, reg, (1U << bit));
1838 	else
1839 		SXISET4(sc, reg, (1U << bit));
1840 }
1841