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