xref: /openbsd-src/sys/dev/fdt/sxiccmu.c (revision c90a81c56dcebd6a1b73fe4aff9b03385b8e63b3)
1 /*	$OpenBSD: sxiccmu.c,v 1.21 2018/08/03 21:28:28 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_r40_get_frequency(struct sxiccmu_softc *, uint32_t);
105 int	sxiccmu_r40_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t);
106 uint32_t sxiccmu_nop_get_frequency(struct sxiccmu_softc *, uint32_t);
107 int	sxiccmu_nop_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t);
108 
109 int
110 sxiccmu_match(struct device *parent, void *match, void *aux)
111 {
112 	struct fdt_attach_args *faa = aux;
113 	int node = faa->fa_node;
114 
115 	if (node == OF_finddevice("/clocks")) {
116 		node = OF_parent(node);
117 
118 		return (OF_is_compatible(node, "allwinner,sun4i-a10") ||
119 		    OF_is_compatible(node, "allwinner,sun5i-a10s") ||
120 		    OF_is_compatible(node, "allwinner,sun5i-r8") ||
121 		    OF_is_compatible(node, "allwinner,sun7i-a20") ||
122 		    OF_is_compatible(node, "allwinner,sun8i-a23") ||
123 		    OF_is_compatible(node, "allwinner,sun8i-a33") ||
124 		    OF_is_compatible(node, "allwinner,sun8i-h3") ||
125 		    OF_is_compatible(node, "allwinner,sun9i-a80") ||
126 		    OF_is_compatible(node, "allwinner,sun50i-a64") ||
127 		    OF_is_compatible(node, "allwinner,sun50i-h5"));
128 	}
129 
130 	return (OF_is_compatible(node, "allwinner,sun4i-a10-ccu") ||
131 	    OF_is_compatible(node, "allwinner,sun7i-a20-ccu") ||
132 	    OF_is_compatible(node, "allwinner,sun8i-a23-ccu") ||
133 	    OF_is_compatible(node, "allwinner,sun8i-a23-prcm") ||
134 	    OF_is_compatible(node, "allwinner,sun8i-a33-ccu") ||
135 	    OF_is_compatible(node, "allwinner,sun8i-h3-ccu") ||
136 	    OF_is_compatible(node, "allwinner,sun8i-h3-r-ccu") ||
137 	    OF_is_compatible(node, "allwinner,sun8i-r40-ccu") ||
138 	    OF_is_compatible(node, "allwinner,sun9i-a80-ccu") ||
139 	    OF_is_compatible(node, "allwinner,sun9i-a80-usb-clks") ||
140 	    OF_is_compatible(node, "allwinner,sun9i-a80-mmc-config-clk") ||
141 	    OF_is_compatible(node, "allwinner,sun50i-a64-ccu") ||
142 	    OF_is_compatible(node, "allwinner,sun50i-a64-r-ccu") ||
143 	    OF_is_compatible(node, "allwinner,sun50i-h5-ccu"));
144 }
145 
146 void
147 sxiccmu_attach(struct device *parent, struct device *self, void *aux)
148 {
149 	struct sxiccmu_softc *sc = (struct sxiccmu_softc *)self;
150 	struct fdt_attach_args *faa = aux;
151 	int node = faa->fa_node;
152 
153 	sc->sc_node = faa->fa_node;
154 	sc->sc_iot = faa->fa_iot;
155 	if (faa->fa_nreg > 0 && bus_space_map(sc->sc_iot,
156 	    faa->fa_reg[0].addr, faa->fa_reg[0].size, 0, &sc->sc_ioh))
157 		panic("%s: bus_space_map failed!", __func__);
158 
159 	/* On the R40, the GMAC needs to poke at one of our registers. */
160 	if (OF_is_compatible(node, "allwinner,sun8i-r40-ccu")) {
161 		bus_space_handle_t ioh;
162 
163 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
164 		    R40_GMAC_CLK_REG, 4, &ioh);
165 		regmap_register(faa->fa_node, sc->sc_iot, ioh, 4);
166 	}
167 
168 	printf("\n");
169 
170 	if (OF_is_compatible(node, "allwinner,sun4i-a10-ccu") ||
171 	    OF_is_compatible(node, "allwinner,sun7i-a20-ccu")) {
172 		KASSERT(faa->fa_nreg > 0);
173 		sc->sc_gates = sun4i_a10_gates;
174 		sc->sc_ngates = nitems(sun4i_a10_gates);
175 		sc->sc_resets = sun4i_a10_resets;
176 		sc->sc_nresets = nitems(sun4i_a10_resets);
177 		sc->sc_get_frequency = sxiccmu_a10_get_frequency;
178 		sc->sc_set_frequency = sxiccmu_a10_set_frequency;
179 	} else if (OF_is_compatible(node, "allwinner,sun8i-a23-ccu") ||
180 	    OF_is_compatible(node, "allwinner,sun8i-a33-ccu")) {
181 		KASSERT(faa->fa_nreg > 0);
182 		sc->sc_gates = sun8i_a23_gates;
183 		sc->sc_ngates = nitems(sun8i_a23_gates);
184 		sc->sc_resets = sun8i_a23_resets;
185 		sc->sc_nresets = nitems(sun8i_a23_resets);
186 		sc->sc_get_frequency = sxiccmu_a23_get_frequency;
187 		sc->sc_set_frequency = sxiccmu_a23_set_frequency;
188 	} else if (OF_is_compatible(node, "allwinner,sun8i-h3-ccu") ||
189 	    OF_is_compatible(node, "allwinner,sun50i-h5-ccu")) {
190 		KASSERT(faa->fa_nreg > 0);
191 		sc->sc_gates = sun8i_h3_gates;
192 		sc->sc_ngates = nitems(sun8i_h3_gates);
193 		sc->sc_resets = sun8i_h3_resets;
194 		sc->sc_nresets = nitems(sun8i_h3_resets);
195 		sc->sc_get_frequency = sxiccmu_h3_get_frequency;
196 		sc->sc_set_frequency = sxiccmu_h3_set_frequency;
197 	} else if (OF_is_compatible(node, "allwinner,sun8i-h3-r-ccu") ||
198 	    OF_is_compatible(node, "allwinner,sun50i-a64-r-ccu")) {
199 		KASSERT(faa->fa_nreg > 0);
200 		sc->sc_gates = sun8i_h3_r_gates;
201 		sc->sc_ngates = nitems(sun8i_h3_r_gates);
202 		sc->sc_resets = sun8i_h3_r_resets;
203 		sc->sc_nresets = nitems(sun8i_h3_r_resets);
204 		sc->sc_get_frequency = sxiccmu_h3_r_get_frequency;
205 		sc->sc_set_frequency = sxiccmu_nop_set_frequency;
206 	} else if (OF_is_compatible(node, "allwinner,sun8i-r40-ccu")) {
207 		KASSERT(faa->fa_nreg > 0);
208 		sc->sc_gates = sun8i_r40_gates;
209 		sc->sc_ngates = nitems(sun8i_r40_gates);
210 		sc->sc_resets = sun8i_r40_resets;
211 		sc->sc_nresets = nitems(sun8i_r40_resets);
212 		sc->sc_get_frequency = sxiccmu_r40_get_frequency;
213 		sc->sc_set_frequency = sxiccmu_r40_set_frequency;
214 	} else if (OF_is_compatible(node, "allwinner,sun9i-a80-ccu")) {
215 		KASSERT(faa->fa_nreg > 0);
216 		sc->sc_gates = sun9i_a80_gates;
217 		sc->sc_ngates = nitems(sun9i_a80_gates);
218 		sc->sc_resets = sun9i_a80_resets;
219 		sc->sc_nresets = nitems(sun9i_a80_resets);
220 		sc->sc_get_frequency = sxiccmu_a80_get_frequency;
221 		sc->sc_set_frequency = sxiccmu_a80_set_frequency;
222 	} else if (OF_is_compatible(node, "allwinner,sun9i-a80-usb-clks")) {
223 		KASSERT(faa->fa_nreg > 0);
224 		sc->sc_gates = sun9i_a80_usb_gates;
225 		sc->sc_ngates = nitems(sun9i_a80_usb_gates);
226 		sc->sc_resets = sun9i_a80_usb_resets;
227 		sc->sc_nresets = nitems(sun9i_a80_usb_resets);
228 		sc->sc_get_frequency = sxiccmu_nop_get_frequency;
229 		sc->sc_set_frequency = sxiccmu_nop_set_frequency;
230 	} else if (OF_is_compatible(node, "allwinner,sun9i-a80-mmc-config-clk")) {
231 		KASSERT(faa->fa_nreg > 0);
232 		sc->sc_gates = sun9i_a80_mmc_gates;
233 		sc->sc_ngates = nitems(sun9i_a80_mmc_gates);
234 		sc->sc_resets = sun9i_a80_mmc_resets;
235 		sc->sc_nresets = nitems(sun9i_a80_mmc_resets);
236 		sc->sc_get_frequency = sxiccmu_nop_get_frequency;
237 		sc->sc_set_frequency = sxiccmu_nop_set_frequency;
238 	} else if (OF_is_compatible(node, "allwinner,sun50i-a64-ccu")) {
239 		KASSERT(faa->fa_nreg > 0);
240 		sc->sc_gates = sun50i_a64_gates;
241 		sc->sc_ngates = nitems(sun50i_a64_gates);
242 		sc->sc_resets = sun50i_a64_resets;
243 		sc->sc_nresets = nitems(sun50i_a64_resets);
244 		sc->sc_get_frequency = sxiccmu_a64_get_frequency;
245 		sc->sc_set_frequency = sxiccmu_a64_set_frequency;
246 	} else {
247 		for (node = OF_child(node); node; node = OF_peer(node))
248 			sxiccmu_attach_clock(sc, node, faa->fa_nreg);
249 	}
250 
251 	if (sc->sc_gates) {
252 		sc->sc_cd.cd_node = sc->sc_node;
253 		sc->sc_cd.cd_cookie = sc;
254 		sc->sc_cd.cd_get_frequency = sxiccmu_ccu_get_frequency;
255 		sc->sc_cd.cd_set_frequency = sxiccmu_ccu_set_frequency;
256 		sc->sc_cd.cd_enable = sxiccmu_ccu_enable;
257 		clock_register(&sc->sc_cd);
258 	}
259 
260 	if (sc->sc_resets) {
261 		sc->sc_rd.rd_node = sc->sc_node;
262 		sc->sc_rd.rd_cookie = sc;
263 		sc->sc_rd.rd_reset = sxiccmu_ccu_reset;
264 		reset_register(&sc->sc_rd);
265 	}
266 }
267 
268 /*
269  * Classic device trees for the Allwinner SoCs have basically a clock
270  * node per register of the clock control unit.  Attaching a separate
271  * driver to each of them would be crazy, so we handle them here.
272  */
273 
274 struct sxiccmu_clock {
275 	int sc_node;
276 	bus_space_tag_t sc_iot;
277 	bus_space_handle_t sc_ioh;
278 
279 	struct clock_device sc_cd;
280 	struct reset_device sc_rd;
281 };
282 
283 struct sxiccmu_device {
284 	const char *compat;
285 	uint32_t (*get_frequency)(void *, uint32_t *);
286 	int	(*set_frequency)(void *, uint32_t *, uint32_t);
287 	void	(*enable)(void *, uint32_t *, int);
288 	void	(*reset)(void *, uint32_t *, int);
289 	bus_size_t offset;
290 };
291 
292 uint32_t sxiccmu_gen_get_frequency(void *, uint32_t *);
293 uint32_t sxiccmu_osc_get_frequency(void *, uint32_t *);
294 uint32_t sxiccmu_pll6_get_frequency(void *, uint32_t *);
295 void	sxiccmu_pll6_enable(void *, uint32_t *, int);
296 uint32_t sxiccmu_apb1_get_frequency(void *, uint32_t *);
297 uint32_t sxiccmu_cpus_get_frequency(void *, uint32_t *);
298 uint32_t sxiccmu_apbs_get_frequency(void *, uint32_t *);
299 int	sxiccmu_gmac_set_frequency(void *, uint32_t *, uint32_t);
300 int	sxiccmu_mmc_set_frequency(void *, uint32_t *, uint32_t);
301 void	sxiccmu_mmc_enable(void *, uint32_t *, int);
302 void	sxiccmu_gate_enable(void *, uint32_t *, int);
303 void	sxiccmu_reset(void *, uint32_t *, int);
304 
305 struct sxiccmu_device sxiccmu_devices[] = {
306 	{
307 		.compat = "allwinner,sun4i-a10-osc-clk",
308 		.get_frequency = sxiccmu_osc_get_frequency,
309 	},
310 	{
311 		.compat = "allwinner,sun4i-a10-pll6-clk",
312 		.get_frequency = sxiccmu_pll6_get_frequency,
313 		.enable = sxiccmu_pll6_enable
314 	},
315 	{
316 		.compat = "allwinner,sun4i-a10-apb1-clk",
317 		.get_frequency = sxiccmu_apb1_get_frequency,
318 	},
319 	{
320 		.compat = "allwinner,sun4i-a10-ahb-gates-clk",
321 		.get_frequency = sxiccmu_gen_get_frequency,
322 		.enable = sxiccmu_gate_enable
323 	},
324 	{
325 		.compat = "allwinner,sun4i-a10-apb0-gates-clk",
326 		.get_frequency = sxiccmu_gen_get_frequency,
327 		.enable = sxiccmu_gate_enable
328 	},
329 	{
330 		.compat = "allwinner,sun4i-a10-apb1-gates-clk",
331 		.get_frequency = sxiccmu_gen_get_frequency,
332 		.enable = sxiccmu_gate_enable
333 	},
334 	{
335 		.compat = "allwinner,sun4i-a10-mmc-clk",
336 		.set_frequency = sxiccmu_mmc_set_frequency,
337 		.enable = sxiccmu_mmc_enable
338 	},
339 	{
340 		.compat = "allwinner,sun4i-a10-usb-clk",
341 		.get_frequency = sxiccmu_gen_get_frequency,
342 		.enable = sxiccmu_gate_enable,
343 		.reset = sxiccmu_reset
344 	},
345 	{
346 		.compat = "allwinner,sun5i-a10s-ahb-gates-clk",
347 		.get_frequency = sxiccmu_gen_get_frequency,
348 		.enable = sxiccmu_gate_enable
349 	},
350 	{
351 		.compat = "allwinner,sun5i-a10s-apb0-gates-clk",
352 		.get_frequency = sxiccmu_gen_get_frequency,
353 		.enable = sxiccmu_gate_enable
354 	},
355 	{
356 		.compat = "allwinner,sun5i-a10s-apb1-gates-clk",
357 		.get_frequency = sxiccmu_gen_get_frequency,
358 		.enable = sxiccmu_gate_enable
359 	},
360 	{
361 		.compat = "allwinner,sun5i-a13-ahb-gates-clk",
362 		.get_frequency = sxiccmu_gen_get_frequency,
363 		.enable = sxiccmu_gate_enable
364 	},
365 	{
366 		.compat = "allwinner,sun5i-a13-apb0-gates-clk",
367 		.get_frequency = sxiccmu_gen_get_frequency,
368 		.enable = sxiccmu_gate_enable
369 	},
370 	{
371 		.compat = "allwinner,sun5i-a13-apb1-gates-clk",
372 		.get_frequency = sxiccmu_gen_get_frequency,
373 		.enable = sxiccmu_gate_enable
374 	},
375 	{
376 		.compat = "allwinner,sun5i-a13-usb-clk",
377 		.get_frequency = sxiccmu_gen_get_frequency,
378 		.enable = sxiccmu_gate_enable,
379 		.reset = sxiccmu_reset
380 	},
381 	{
382 		.compat = "allwinner,sun6i-a31-ahb1-reset",
383 		.reset = sxiccmu_reset
384 	},
385 	{
386 		.compat = "allwinner,sun6i-a31-clock-reset",
387 		.reset = sxiccmu_reset,
388 		.offset = 0x00b0
389 	},
390 	{
391 		.compat = "allwinner,sun7i-a20-ahb-gates-clk",
392 		.get_frequency = sxiccmu_gen_get_frequency,
393 		.enable = sxiccmu_gate_enable
394 	},
395 	{
396 		.compat = "allwinner,sun7i-a20-apb0-gates-clk",
397 		.get_frequency = sxiccmu_gen_get_frequency,
398 		.enable = sxiccmu_gate_enable
399 	},
400 	{
401 		.compat = "allwinner,sun7i-a20-apb1-gates-clk",
402 		.get_frequency = sxiccmu_gen_get_frequency,
403 		.enable = sxiccmu_gate_enable
404 	},
405 	{
406 		.compat = "allwinner,sun7i-a20-gmac-clk",
407 		.set_frequency = sxiccmu_gmac_set_frequency
408 	},
409 	{
410 		.compat = "allwinner,sun8i-a23-apb0-clk",
411 		.get_frequency = sxiccmu_apbs_get_frequency,
412 		.offset = 0x000c
413 	},
414 	{
415 		.compat = "allwinner,sun8i-a23-ahb1-gates-clk",
416 		.get_frequency = sxiccmu_gen_get_frequency,
417 		.enable = sxiccmu_gate_enable
418 	},
419 	{
420 		.compat = "allwinner,sun8i-a23-apb0-gates-clk",
421 		.get_frequency = sxiccmu_gen_get_frequency,
422 		.enable = sxiccmu_gate_enable,
423 		.offset = 0x0028
424 	},
425 	{
426 		.compat = "allwinner,sun8i-a23-apb1-gates-clk",
427 		.get_frequency = sxiccmu_gen_get_frequency,
428 		.enable = sxiccmu_gate_enable
429 	},
430 	{
431 		.compat = "allwinner,sun8i-a23-apb2-gates-clk",
432 		.get_frequency = sxiccmu_gen_get_frequency,
433 		.enable = sxiccmu_gate_enable
434 	},
435 	{
436 		.compat = "allwinner,sun8i-a23-usb-clk",
437 		.get_frequency = sxiccmu_gen_get_frequency,
438 		.enable = sxiccmu_gate_enable,
439 		.reset = sxiccmu_reset
440 	},
441 	{
442 		.compat = "allwinner,sun8i-h3-apb0-gates-clk",
443 		.get_frequency = sxiccmu_gen_get_frequency,
444 		.enable = sxiccmu_gate_enable
445 	},
446 	{
447 		.compat = "allwinner,sun9i-a80-apb1-clk",
448 		.get_frequency = sxiccmu_apb1_get_frequency,
449 	},
450 	{
451 		.compat = "allwinner,sun9i-a80-ahb0-gates-clk",
452 		.get_frequency = sxiccmu_gen_get_frequency,
453 		.enable = sxiccmu_gate_enable
454 	},
455 	{
456 		.compat = "allwinner,sun9i-a80-ahb1-gates-clk",
457 		.get_frequency = sxiccmu_gen_get_frequency,
458 		.enable = sxiccmu_gate_enable
459 	},
460 	{
461 		.compat = "allwinner,sun9i-a80-ahb2-gates-clk",
462 		.get_frequency = sxiccmu_gen_get_frequency,
463 		.enable = sxiccmu_gate_enable
464 	},
465 	{
466 		.compat = "allwinner,sun9i-a80-apb0-gates-clk",
467 		.get_frequency = sxiccmu_gen_get_frequency,
468 		.enable = sxiccmu_gate_enable
469 	},
470 	{
471 		.compat = "allwinner,sun9i-a80-apb1-gates-clk",
472 		.get_frequency = sxiccmu_gen_get_frequency,
473 		.enable = sxiccmu_gate_enable
474 	},
475 	{
476 		.compat = "allwinner,sun9i-a80-apbs-gates-clk",
477 		.get_frequency = sxiccmu_gen_get_frequency,
478 		.enable = sxiccmu_gate_enable
479 	},
480 	{
481 		.compat = "allwinner,sun9i-a80-cpus-clk",
482 		.get_frequency = sxiccmu_cpus_get_frequency
483 	},
484 	{
485 		.compat = "allwinner,sun9i-a80-mmc-clk",
486 		.set_frequency = sxiccmu_mmc_set_frequency,
487 		.enable = sxiccmu_mmc_enable
488 	},
489 	{
490 		.compat = "allwinner,sun9i-a80-usb-mod-clk",
491 		.get_frequency = sxiccmu_gen_get_frequency,
492 		.enable = sxiccmu_gate_enable,
493 		.reset = sxiccmu_reset
494 	},
495 	{
496 		.compat = "allwinner,sun9i-a80-usb-phy-clk",
497 		.get_frequency = sxiccmu_gen_get_frequency,
498 		.enable = sxiccmu_gate_enable,
499 		.reset = sxiccmu_reset
500 	},
501 };
502 
503 void
504 sxiccmu_attach_clock(struct sxiccmu_softc *sc, int node, int nreg)
505 {
506 	struct sxiccmu_clock *clock;
507 	uint32_t reg[2];
508 	int i, error = ENODEV;
509 
510 	for (i = 0; i < nitems(sxiccmu_devices); i++)
511 		if (OF_is_compatible(node, sxiccmu_devices[i].compat))
512 			break;
513 	if (i == nitems(sxiccmu_devices))
514 		return;
515 
516 	clock = malloc(sizeof(*clock), M_DEVBUF, M_WAITOK);
517 	clock->sc_node = node;
518 
519 	clock->sc_iot = sc->sc_iot;
520 	if (OF_getpropintarray(node, "reg", reg, sizeof(reg)) == sizeof(reg)) {
521 		error = bus_space_map(clock->sc_iot, reg[0], reg[1], 0,
522 		    &clock->sc_ioh);
523 	} else if (nreg > 0) {
524 		error = bus_space_subregion(clock->sc_iot, sc->sc_ioh,
525 		    sxiccmu_devices[i].offset, 4, &clock->sc_ioh);
526 	}
527 	if (error) {
528 		printf("%s: can't map registers", sc->sc_dev.dv_xname);
529 		free(clock, M_DEVBUF, sizeof(*clock));
530 		return;
531 	}
532 
533 	clock->sc_cd.cd_node = node;
534 	clock->sc_cd.cd_cookie = clock;
535 	clock->sc_cd.cd_get_frequency = sxiccmu_devices[i].get_frequency;
536 	clock->sc_cd.cd_set_frequency = sxiccmu_devices[i].set_frequency;
537 	clock->sc_cd.cd_enable = sxiccmu_devices[i].enable;
538 	clock_register(&clock->sc_cd);
539 
540 	if (sxiccmu_devices[i].reset) {
541 		clock->sc_rd.rd_node = node;
542 		clock->sc_rd.rd_cookie = clock;
543 		clock->sc_rd.rd_reset = sxiccmu_devices[i].reset;
544 		reset_register(&clock->sc_rd);
545 	}
546 }
547 
548 /*
549  * A "generic" function that simply gets the clock frequency from the
550  * parent clock.  Useful for clock gating devices that don't scale
551  * their clocks.
552  */
553 uint32_t
554 sxiccmu_gen_get_frequency(void *cookie, uint32_t *cells)
555 {
556 	struct sxiccmu_clock *sc = cookie;
557 
558 	return clock_get_frequency(sc->sc_node, NULL);
559 }
560 
561 uint32_t
562 sxiccmu_osc_get_frequency(void *cookie, uint32_t *cells)
563 {
564 	struct sxiccmu_clock *sc = cookie;
565 
566 	return OF_getpropint(sc->sc_node, "clock-frequency", 24000000);
567 }
568 
569 #define CCU_PLL6_ENABLE			(1U << 31)
570 #define CCU_PLL6_BYPASS_EN		(1U << 30)
571 #define CCU_PLL6_SATA_CLK_EN		(1U << 14)
572 #define CCU_PLL6_FACTOR_N(x)		(((x) >> 8) & 0x1f)
573 #define CCU_PLL6_FACTOR_N_MASK		(0x1f << 8)
574 #define CCU_PLL6_FACTOR_N_SHIFT		8
575 #define CCU_PLL6_FACTOR_K(x)		(((x) >> 4) & 0x3)
576 #define CCU_PLL6_FACTOR_K_MASK		(0x3 << 4)
577 #define CCU_PLL6_FACTOR_K_SHIFT		4
578 #define CCU_PLL6_FACTOR_M(x)		(((x) >> 0) & 0x3)
579 #define CCU_PLL6_FACTOR_M_MASK		(0x3 << 0)
580 #define CCU_PLL6_FACTOR_M_SHIFT		0
581 
582 uint32_t
583 sxiccmu_pll6_get_frequency(void *cookie, uint32_t *cells)
584 {
585 	struct sxiccmu_clock *sc = cookie;
586 	uint32_t reg, k, m, n, freq;
587 	uint32_t idx = cells[0];
588 
589 	/* XXX Assume bypass is disabled. */
590 	reg = SXIREAD4(sc, 0);
591 	k = CCU_PLL6_FACTOR_K(reg) + 1;
592 	m = CCU_PLL6_FACTOR_M(reg) + 1;
593 	n = CCU_PLL6_FACTOR_N(reg);
594 
595 	freq = clock_get_frequency_idx(sc->sc_node, 0);
596 	switch (idx) {
597 	case 0:
598 		return (freq * n * k) / m / 6;		/* pll6_sata */
599 	case 1:
600 		return (freq * n * k) / 2;		/* pll6_other */
601 	case 2:
602 		return (freq * n * k);			/* pll6 */
603 	case 3:
604 		return (freq * n * k) / 4;		/* pll6_div_4 */
605 	}
606 
607 	return 0;
608 }
609 
610 void
611 sxiccmu_pll6_enable(void *cookie, uint32_t *cells, int on)
612 {
613 	struct sxiccmu_clock *sc = cookie;
614 	uint32_t idx = cells[0];
615 	uint32_t reg;
616 
617 	/*
618 	 * Since this clock has several outputs, we never turn it off.
619 	 */
620 
621 	reg = SXIREAD4(sc, 0);
622 	switch (idx) {
623 	case 0:			/* pll6_sata */
624 		if (on)
625 			reg |= CCU_PLL6_SATA_CLK_EN;
626 		else
627 			reg &= ~CCU_PLL6_SATA_CLK_EN;
628 		/* FALLTHROUGH */
629 	case 1:			/* pll6_other */
630 	case 2:			/* pll6 */
631 	case 3:			/* pll6_div_4 */
632 		if (on)
633 			reg |= CCU_PLL6_ENABLE;
634 	}
635 	SXIWRITE4(sc, 0, reg);
636 }
637 
638 #define CCU_APB1_CLK_RAT_N(x)		(((x) >> 16) & 0x3)
639 #define CCU_APB1_CLK_RAT_M(x)		(((x) >> 0) & 0x1f)
640 #define CCU_APB1_CLK_SRC_SEL(x)		(((x) >> 24) & 0x3)
641 
642 uint32_t
643 sxiccmu_apb1_get_frequency(void *cookie, uint32_t *cells)
644 {
645 	struct sxiccmu_clock *sc = cookie;
646 	uint32_t reg, m, n, freq;
647 	int idx;
648 
649 	reg = SXIREAD4(sc, 0);
650 	m = CCU_APB1_CLK_RAT_M(reg);
651 	n = CCU_APB1_CLK_RAT_N(reg);
652 	idx = CCU_APB1_CLK_SRC_SEL(reg);
653 
654 	freq = clock_get_frequency_idx(sc->sc_node, idx);
655 	return freq / (1 << n) / (m + 1);
656 }
657 
658 #define CCU_CPUS_CLK_SRC_SEL(x)		(((x) >> 16) & 0x3)
659 #define CCU_CPUS_POST_DIV(x)		(((x) >> 8) & 0x1f)
660 #define CCU_CPUS_CLK_RATIO(x)		(((x) >> 0) & 0x3)
661 
662 uint32_t
663 sxiccmu_cpus_get_frequency(void *cookie, uint32_t *cells)
664 {
665 	struct sxiccmu_clock *sc = cookie;
666 	uint32_t reg, post_div, clk_ratio, freq;
667 	int idx;
668 
669 	reg = SXIREAD4(sc, 0);
670 	idx = CCU_CPUS_CLK_SRC_SEL(reg);
671 	post_div = (idx == 2 ? CCU_CPUS_POST_DIV(reg): 0);
672 	clk_ratio = CCU_CPUS_CLK_RATIO(reg);
673 
674 	freq = clock_get_frequency_idx(sc->sc_node, idx);
675 	return freq / (clk_ratio + 1) / (post_div + 1);
676 }
677 
678 #define CCU_APBS_CLK_RATIO(x)		(((x) >> 0) & 0x3)
679 
680 uint32_t
681 sxiccmu_apbs_get_frequency(void *cookie, uint32_t *cells)
682 {
683 	struct sxiccmu_clock *sc = cookie;
684 	uint32_t reg, freq;
685 
686 	reg = SXIREAD4(sc, 0);
687 	freq = clock_get_frequency(sc->sc_node, NULL);
688 	return freq / (CCU_APBS_CLK_RATIO(reg) + 1);
689 }
690 
691 #define	CCU_GMAC_CLK_PIT		(1 << 2)
692 #define	CCU_GMAC_CLK_TCS		(3 << 0)
693 #define	CCU_GMAC_CLK_TCS_MII		0
694 #define	CCU_GMAC_CLK_TCS_EXT_125	1
695 #define	CCU_GMAC_CLK_TCS_INT_RGMII	2
696 
697 int
698 sxiccmu_gmac_set_frequency(void *cookie, uint32_t *cells, uint32_t freq)
699 {
700 	struct sxiccmu_clock *sc = cookie;
701 
702 	switch (freq) {
703 	case 25000000:		/* MMI, 25 MHz */
704 		SXICMS4(sc, 0, CCU_GMAC_CLK_PIT|CCU_GMAC_CLK_TCS,
705 		    CCU_GMAC_CLK_TCS_MII);
706 		break;
707 	case 125000000:		/* RGMII, 125 MHz */
708 		SXICMS4(sc, 0, CCU_GMAC_CLK_PIT|CCU_GMAC_CLK_TCS,
709 		    CCU_GMAC_CLK_PIT|CCU_GMAC_CLK_TCS_INT_RGMII);
710 		break;
711 	default:
712 		return -1;
713 	}
714 
715 	return 0;
716 }
717 
718 #define CCU_SDx_SCLK_GATING		(1U << 31)
719 #define CCU_SDx_CLK_SRC_SEL_OSC24M	(0 << 24)
720 #define CCU_SDx_CLK_SRC_SEL_PLL6	(1 << 24)
721 #define CCU_SDx_CLK_SRC_SEL_PLL5	(2 << 24)
722 #define CCU_SDx_CLK_SRC_SEL_MASK	(3 << 24)
723 #define CCU_SDx_CLK_DIV_RATIO_N_MASK	(3 << 16)
724 #define CCU_SDx_CLK_DIV_RATIO_N_SHIFT	16
725 #define CCU_SDx_CLK_DIV_RATIO_M_MASK	(7 << 0)
726 #define CCU_SDx_CLK_DIV_RATIO_M_SHIFT	0
727 
728 int
729 sxiccmu_mmc_do_set_frequency(struct sxiccmu_clock *sc, uint32_t freq,
730     uint32_t parent_freq)
731 {
732 	uint32_t reg, m, n;
733 	uint32_t clk_src;
734 
735 	switch (freq) {
736 	case 400000:
737 		n = 2, m = 15;
738 		clk_src = CCU_SDx_CLK_SRC_SEL_OSC24M;
739 		break;
740 	case 20000000:
741 	case 25000000:
742 	case 26000000:
743 	case 50000000:
744 	case 52000000:
745 		n = 0, m = 0;
746 		clk_src = CCU_SDx_CLK_SRC_SEL_PLL6;
747 		while ((parent_freq / (1 << n) / 16) > freq)
748 			n++;
749 		while ((parent_freq / (1 << n) / (m + 1)) > freq)
750 			m++;
751 		break;
752 	default:
753 		return -1;
754 	}
755 
756 	reg = SXIREAD4(sc, 0);
757 	reg &= ~CCU_SDx_CLK_SRC_SEL_MASK;
758 	reg |= clk_src;
759 	reg &= ~CCU_SDx_CLK_DIV_RATIO_N_MASK;
760 	reg |= n << CCU_SDx_CLK_DIV_RATIO_N_SHIFT;
761 	reg &= ~CCU_SDx_CLK_DIV_RATIO_M_MASK;
762 	reg |= m << CCU_SDx_CLK_DIV_RATIO_M_SHIFT;
763 	SXIWRITE4(sc, 0, reg);
764 
765 	return 0;
766 }
767 
768 int
769 sxiccmu_mmc_set_frequency(void *cookie, uint32_t *cells, uint32_t freq)
770 {
771 	struct sxiccmu_clock *sc = cookie;
772 	uint32_t parent_freq;
773 
774 	if (cells[0] != 0)
775 		return -1;
776 
777 	parent_freq = clock_get_frequency_idx(sc->sc_node, 1);
778 	return sxiccmu_mmc_do_set_frequency(sc, freq, parent_freq);
779 }
780 
781 void
782 sxiccmu_mmc_enable(void *cookie, uint32_t *cells, int on)
783 {
784 	struct sxiccmu_clock *sc = cookie;
785 
786 	if (cells[0] != 0)
787 		return;
788 
789 	if (on)
790 		SXISET4(sc, 0, CCU_SDx_SCLK_GATING);
791 	else
792 		SXICLR4(sc, 0, CCU_SDx_SCLK_GATING);
793 }
794 
795 void
796 sxiccmu_gate_enable(void *cookie, uint32_t *cells, int on)
797 {
798 	struct sxiccmu_clock *sc = cookie;
799 	int reg = cells[0] / 32;
800 	int bit = cells[0] % 32;
801 
802 	if (on) {
803 		clock_enable(sc->sc_node, NULL);
804 		SXISET4(sc, reg * 4, (1U << bit));
805 	} else {
806 		SXICLR4(sc, reg * 4, (1U << bit));
807 		clock_disable(sc->sc_node, NULL);
808 	}
809 }
810 
811 void
812 sxiccmu_reset(void *cookie, uint32_t *cells, int assert)
813 {
814 	struct sxiccmu_clock *sc = cookie;
815 	int reg = cells[0] / 32;
816 	int bit = cells[0] % 32;
817 
818 	if (assert)
819 		SXICLR4(sc, reg * 4, (1U << bit));
820 	else
821 		SXISET4(sc, reg * 4, (1U << bit));
822 }
823 
824 /*
825  * Newer device trees, such as those for the Allwinner H3/A64 have
826  * most of the clock nodes replaced with a single clock control unit
827  * node.
828  */
829 
830 uint32_t
831 sxiccmu_ccu_get_frequency(void *cookie, uint32_t *cells)
832 {
833 	struct sxiccmu_softc *sc = cookie;
834 	uint32_t idx = cells[0];
835 	uint32_t parent;
836 
837 	if (idx < sc->sc_ngates && sc->sc_gates[idx].parent) {
838 		parent = sc->sc_gates[idx].parent;
839 		return sxiccmu_ccu_get_frequency(sc, &parent);
840 	}
841 
842 	return sc->sc_get_frequency(sc, idx);
843 }
844 
845 /* Allwinner A10/A20 */
846 #define A10_PLL1_CFG_REG		0x0000
847 #define A10_PLL1_OUT_EXT_DIVP(x)	(((x) >> 16) & 0x3)
848 #define A10_PLL1_FACTOR_N(x)		(((x) >> 8) & 0x1f)
849 #define A10_PLL1_FACTOR_K(x)		(((x) >> 4) & 0x3)
850 #define A10_PLL1_FACTOR_M(x)		(((x) >> 0) & 0x3)
851 #define A10_CPU_AHB_APB0_CFG_REG	0x0054
852 #define A10_CPU_CLK_SRC_SEL		(0x3 << 16)
853 #define A10_CPU_CLK_SRC_SEL_LOSC	(0x0 << 16)
854 #define A10_CPU_CLK_SRC_SEL_OSC24M	(0x1 << 16)
855 #define A10_CPU_CLK_SRC_SEL_PLL1	(0x2 << 16)
856 #define A10_CPU_CLK_SRC_SEL_200MHZ	(0x3 << 16)
857 
858 uint32_t
859 sxiccmu_a10_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
860 {
861 	uint32_t parent;
862 	uint32_t reg, k, m, n, p;
863 
864 	switch (idx) {
865 	case A10_CLK_LOSC:
866 		return clock_get_frequency(sc->sc_node, "losc");
867 	case A10_CLK_HOSC:
868 		return clock_get_frequency(sc->sc_node, "hosc");
869 	case A10_CLK_PLL_CORE:
870 		reg = SXIREAD4(sc, A10_PLL1_CFG_REG);
871 		k = A10_PLL1_FACTOR_K(reg) + 1;
872 		m = A10_PLL1_FACTOR_M(reg) + 1;
873 		n = A10_PLL1_FACTOR_N(reg);
874 		p = 1 << A10_PLL1_OUT_EXT_DIVP(reg);
875 		return (24000000 * n * k) / (m * p);
876 	case A10_CLK_PLL_PERIPH_BASE:
877 		/* Not hardcoded, but recommended. */
878 		return 600000000;
879 	case A10_CLK_PLL_PERIPH:
880 		return sxiccmu_a10_get_frequency(sc, A10_CLK_PLL_PERIPH_BASE) * 2;
881 	case A10_CLK_CPU:
882 		reg = SXIREAD4(sc, A10_CPU_AHB_APB0_CFG_REG);
883 		switch (reg & A10_CPU_CLK_SRC_SEL) {
884 		case A10_CPU_CLK_SRC_SEL_LOSC:
885 			parent = A10_CLK_LOSC;
886 			break;
887 		case A10_CPU_CLK_SRC_SEL_OSC24M:
888 			parent = A10_CLK_HOSC;
889 			break;
890 		case A10_CPU_CLK_SRC_SEL_PLL1:
891 			parent = A10_CLK_PLL_CORE;
892 			break;
893 		case A10_CPU_CLK_SRC_SEL_200MHZ:
894 			return 200000000;
895 		}
896 		return sxiccmu_ccu_get_frequency(sc, &parent);
897 	case A10_CLK_APB1:
898 		/* XXX Controlled by a MUX. */
899 		return 24000000;
900 	}
901 
902 	printf("%s: 0x%08x\n", __func__, idx);
903 	return 0;
904 }
905 
906 /* Allwinner A23/A64/H3/H5/R40 */
907 #define CCU_AHB1_APB1_CFG_REG		0x0054
908 #define CCU_AHB1_CLK_SRC_SEL		(3 << 12)
909 #define CCU_AHB1_CLK_SRC_SEL_LOSC	(0 << 12)
910 #define CCU_AHB1_CLK_SRC_SEL_OSC24M	(1 << 12)
911 #define CCU_AHB1_CLK_SRC_SEL_AXI	(2 << 12)
912 #define CCU_AHB1_CLK_SRC_SEL_PERIPH0	(3 << 12)
913 #define CCU_AHB1_PRE_DIV(x)		((((x) >> 6) & 3) + 1)
914 #define CCU_AHB1_CLK_DIV_RATIO(x)	(1 << (((x) >> 4) & 3))
915 #define CCU_AHB2_CFG_REG		0x005c
916 #define CCU_AHB2_CLK_CFG		(3 << 0)
917 
918 uint32_t
919 sxiccmu_a23_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
920 {
921 	uint32_t parent;
922 	uint32_t reg, div;
923 
924 	switch (idx) {
925 	case A23_CLK_LOSC:
926 		return clock_get_frequency(sc->sc_node, "losc");
927 	case A23_CLK_HOSC:
928 		return clock_get_frequency(sc->sc_node, "hosc");
929 	case A23_CLK_PLL_PERIPH:
930 		/* Not hardcoded, but recommended. */
931 		return 600000000;
932 	case A23_CLK_APB2:
933 		/* XXX Controlled by a MUX. */
934 		return 24000000;
935 	case A23_CLK_AHB1:
936 		reg = SXIREAD4(sc, CCU_AHB1_APB1_CFG_REG);
937 		div = CCU_AHB1_CLK_DIV_RATIO(reg);
938 		switch (reg & CCU_AHB1_CLK_SRC_SEL) {
939 		case CCU_AHB1_CLK_SRC_SEL_LOSC:
940 			parent = A23_CLK_LOSC;
941 			break;
942 		case CCU_AHB1_CLK_SRC_SEL_OSC24M:
943 			parent = A23_CLK_HOSC;
944 			break;
945 		case CCU_AHB1_CLK_SRC_SEL_AXI:
946 			parent = A23_CLK_AXI;
947 			break;
948 		case CCU_AHB1_CLK_SRC_SEL_PERIPH0:
949 			parent = A23_CLK_PLL_PERIPH;
950 			div *= CCU_AHB1_PRE_DIV(reg);
951 			break;
952 		default:
953 			return 0;
954 		}
955 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
956 	}
957 
958 	printf("%s: 0x%08x\n", __func__, idx);
959 	return 0;
960 }
961 
962 uint32_t
963 sxiccmu_a64_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
964 {
965 	uint32_t parent;
966 	uint32_t reg, div;
967 
968 	switch (idx) {
969 	case A64_CLK_LOSC:
970 		return clock_get_frequency(sc->sc_node, "losc");
971 	case A64_CLK_HOSC:
972 		return clock_get_frequency(sc->sc_node, "hosc");
973 	case A64_CLK_PLL_PERIPH0:
974 		/* Not hardcoded, but recommended. */
975 		return 600000000;
976 	case A64_CLK_PLL_PERIPH0_2X:
977 		return sxiccmu_a64_get_frequency(sc, A64_CLK_PLL_PERIPH0) * 2;
978 	case A64_CLK_APB2:
979 		/* XXX Controlled by a MUX. */
980 		return 24000000;
981 	case A64_CLK_AHB1:
982 		reg = SXIREAD4(sc, CCU_AHB1_APB1_CFG_REG);
983 		div = CCU_AHB1_CLK_DIV_RATIO(reg);
984 		switch (reg & CCU_AHB1_CLK_SRC_SEL) {
985 		case CCU_AHB1_CLK_SRC_SEL_LOSC:
986 			parent = A64_CLK_LOSC;
987 			break;
988 		case CCU_AHB1_CLK_SRC_SEL_OSC24M:
989 			parent = A64_CLK_HOSC;
990 			break;
991 		case CCU_AHB1_CLK_SRC_SEL_AXI:
992 			parent = A64_CLK_AXI;
993 			break;
994 		case CCU_AHB1_CLK_SRC_SEL_PERIPH0:
995 			parent = A64_CLK_PLL_PERIPH0;
996 			div *= CCU_AHB1_PRE_DIV(reg);
997 			break;
998 		default:
999 			return 0;
1000 		}
1001 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
1002 	case A64_CLK_AHB2:
1003 		reg = SXIREAD4(sc, CCU_AHB2_CFG_REG);
1004 		switch (reg & CCU_AHB2_CLK_CFG) {
1005 		case 0:
1006 			parent = A64_CLK_AHB1;
1007 			div = 1;
1008 			break;
1009 		case 1:
1010 			parent = A64_CLK_PLL_PERIPH0;
1011 			div = 2;
1012 			break;
1013 		default:
1014 			return 0;
1015 		}
1016 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
1017 	}
1018 
1019 	printf("%s: 0x%08x\n", __func__, idx);
1020 	return 0;
1021 }
1022 
1023 uint32_t
1024 sxiccmu_a80_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
1025 {
1026 	switch (idx) {
1027 	case A80_CLK_PLL_PERIPH0:
1028 		/* Not hardcoded, but recommended. */
1029 		return 960000000;
1030 	case A80_CLK_APB1:
1031 		/* XXX Controlled by a MUX. */
1032 		return 24000000;
1033 	}
1034 
1035 	printf("%s: 0x%08x\n", __func__, idx);
1036 	return 0;
1037 }
1038 
1039 /* Allwinner H3/H5 */
1040 #define H3_PLL_CPUX_CTRL_REG		0x0000
1041 #define H3_PLL_CPUX_LOCK		(1 << 28)
1042 #define H3_PLL_CPUX_OUT_EXT_DIVP(x)	(((x) >> 16) & 0x3)
1043 #define H3_PLL_CPUX_OUT_EXT_DIVP_MASK	(0x3 << 16)
1044 #define H3_PLL_CPUX_OUT_EXT_DIVP_SHIFT	16
1045 #define H3_PLL_CPUX_FACTOR_N(x)		(((x) >> 8) & 0x1f)
1046 #define H3_PLL_CPUX_FACTOR_N_MASK	(0x1f << 8)
1047 #define H3_PLL_CPUX_FACTOR_N_SHIFT	8
1048 #define H3_PLL_CPUX_FACTOR_K(x)		(((x) >> 4) & 0x3)
1049 #define H3_PLL_CPUX_FACTOR_K_MASK	(0x3 << 4)
1050 #define H3_PLL_CPUX_FACTOR_K_SHIFT	4
1051 #define H3_PLL_CPUX_FACTOR_M(x)		(((x) >> 0) & 0x3)
1052 #define H3_PLL_CPUX_FACTOR_M_MASK	(0x3 << 0)
1053 #define H3_PLL_CPUX_FACTOR_M_SHIFT	0
1054 #define H3_CPUX_AXI_CFG_REG		0x0050
1055 #define H3_CPUX_CLK_SRC_SEL		(0x3 << 16)
1056 #define H3_CPUX_CLK_SRC_SEL_LOSC	(0x0 << 16)
1057 #define H3_CPUX_CLK_SRC_SEL_OSC24M	(0x1 << 16)
1058 #define H3_CPUX_CLK_SRC_SEL_PLL_CPUX	(0x2 << 16)
1059 
1060 uint32_t
1061 sxiccmu_h3_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
1062 {
1063 	uint32_t parent;
1064 	uint32_t reg, div;
1065 	uint32_t k, m, n, p;
1066 
1067 	switch (idx) {
1068 	case H3_CLK_LOSC:
1069 		return clock_get_frequency(sc->sc_node, "losc");
1070 	case H3_CLK_HOSC:
1071 		return clock_get_frequency(sc->sc_node, "hosc");
1072 	case H3_CLK_PLL_CPUX:
1073 		reg = SXIREAD4(sc, H3_PLL_CPUX_CTRL_REG);
1074 		k = H3_PLL_CPUX_FACTOR_K(reg) + 1;
1075 		m = H3_PLL_CPUX_FACTOR_M(reg) + 1;
1076 		n = H3_PLL_CPUX_FACTOR_N(reg) + 1;
1077 		p = 1 << H3_PLL_CPUX_OUT_EXT_DIVP(reg);
1078 		return (24000000 * n * k) / (m * p);
1079 	case H3_CLK_PLL_PERIPH0:
1080 		/* Not hardcoded, but recommended. */
1081 		return 600000000;
1082 	case H3_CLK_CPUX:
1083 		reg = SXIREAD4(sc, H3_CPUX_AXI_CFG_REG);
1084 		switch (reg & H3_CPUX_CLK_SRC_SEL) {
1085 		case H3_CPUX_CLK_SRC_SEL_LOSC:
1086 			parent = H3_CLK_LOSC;
1087 			break;
1088 		case H3_CPUX_CLK_SRC_SEL_OSC24M:
1089 			parent = H3_CLK_HOSC;
1090 			break;
1091 		case H3_CPUX_CLK_SRC_SEL_PLL_CPUX:
1092 			parent = H3_CLK_PLL_CPUX;
1093 			break;
1094 		default:
1095 			return 0;
1096 		}
1097 		return sxiccmu_ccu_get_frequency(sc, &parent);
1098 	case H3_CLK_APB2:
1099 		/* XXX Controlled by a MUX. */
1100 		return 24000000;
1101 	case H3_CLK_AHB1:
1102 		reg = SXIREAD4(sc, CCU_AHB1_APB1_CFG_REG);
1103 		div = CCU_AHB1_CLK_DIV_RATIO(reg);
1104 		switch (reg & CCU_AHB1_CLK_SRC_SEL) {
1105 		case CCU_AHB1_CLK_SRC_SEL_LOSC:
1106 			parent = H3_CLK_LOSC;
1107 			break;
1108 		case CCU_AHB1_CLK_SRC_SEL_OSC24M:
1109 			parent = H3_CLK_HOSC;
1110 			break;
1111 		case CCU_AHB1_CLK_SRC_SEL_AXI:
1112 			parent = H3_CLK_AXI;
1113 			break;
1114 		case CCU_AHB1_CLK_SRC_SEL_PERIPH0:
1115 			parent = H3_CLK_PLL_PERIPH0;
1116 			div *= CCU_AHB1_PRE_DIV(reg);
1117 			break;
1118 		default:
1119 			return 0;
1120 		}
1121 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
1122 	case H3_CLK_AHB2:
1123 		reg = SXIREAD4(sc, CCU_AHB2_CFG_REG);
1124 		switch (reg & CCU_AHB2_CLK_CFG) {
1125 		case 0:
1126 			parent = H3_CLK_AHB1;
1127 			div = 1;
1128 			break;
1129 		case 1:
1130 			parent = H3_CLK_PLL_PERIPH0;
1131 			div = 2;
1132 			break;
1133 		default:
1134 			return 0;
1135 		}
1136 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
1137 	}
1138 
1139 	printf("%s: 0x%08x\n", __func__, idx);
1140 	return 0;
1141 }
1142 
1143 #define H3_AHB0_CLK_REG			0x0000
1144 #define H3_AHB0_CLK_SRC_SEL		(0x3 << 16)
1145 #define H3_AHB0_CLK_SRC_SEL_OSC32K	(0x0 << 16)
1146 #define H3_AHB0_CLK_SRC_SEL_OSC24M	(0x1 << 16)
1147 #define H3_AHB0_CLK_SRC_SEL_PLL_PERIPH0	(0x2 << 16)
1148 #define H3_AHB0_CLK_SRC_SEL_IOSC	(0x3 << 16)
1149 #define H3_AHB0_CLK_PRE_DIV(x)		((((x) >> 8) & 0x1f) + 1)
1150 #define H3_AHB0_CLK_RATIO(x)		(1 << (((x) >> 4) & 3))
1151 #define H3_APB0_CFG_REG			0x000c
1152 #define H3_APB0_CLK_RATIO(x)		(1 << ((x) & 1))
1153 
1154 uint32_t
1155 sxiccmu_h3_r_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
1156 {
1157 	uint32_t parent;
1158 	uint32_t reg, div;
1159 	uint32_t freq;
1160 
1161 	switch (idx) {
1162 	case H3_R_CLK_AHB0:
1163 		reg = SXIREAD4(sc, H3_AHB0_CLK_REG);
1164 		switch (reg & H3_AHB0_CLK_SRC_SEL) {
1165 		case H3_AHB0_CLK_SRC_SEL_OSC32K:
1166 			freq = clock_get_frequency(sc->sc_node, "losc");
1167 			break;
1168 		case H3_AHB0_CLK_SRC_SEL_OSC24M:
1169 			freq = clock_get_frequency(sc->sc_node, "hosc");
1170 			break;
1171 		case H3_AHB0_CLK_SRC_SEL_PLL_PERIPH0:
1172 			freq = clock_get_frequency(sc->sc_node, "pll-periph");
1173 			break;
1174 		case H3_AHB0_CLK_SRC_SEL_IOSC:
1175 			freq = clock_get_frequency(sc->sc_node, "iosc");
1176 			break;
1177 		}
1178 		div = H3_AHB0_CLK_PRE_DIV(reg) * H3_AHB0_CLK_RATIO(reg);
1179 		return freq / div;
1180 	case H3_R_CLK_APB0:
1181 		reg = SXIREAD4(sc, H3_APB0_CFG_REG);
1182 		div = H3_APB0_CLK_RATIO(reg);
1183 		parent = H3_R_CLK_AHB0;
1184 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
1185 	}
1186 
1187 	printf("%s: 0x%08x\n", __func__, idx);
1188 	return 0;
1189 }
1190 
1191 uint32_t
1192 sxiccmu_r40_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
1193 {
1194 	uint32_t parent;
1195 	uint32_t reg, div;
1196 
1197 	switch (idx) {
1198 	case R40_CLK_LOSC:
1199 		return clock_get_frequency(sc->sc_node, "losc");
1200 	case R40_CLK_HOSC:
1201 		return clock_get_frequency(sc->sc_node, "hosc");
1202 	case R40_CLK_PLL_PERIPH0:
1203 		/* Not hardcoded, but recommended. */
1204 		return 600000000;
1205 	case R40_CLK_PLL_PERIPH0_2X:
1206 		return sxiccmu_r40_get_frequency(sc, R40_CLK_PLL_PERIPH0) * 2;
1207 	case R40_CLK_AHB1:
1208 		reg = SXIREAD4(sc, CCU_AHB1_APB1_CFG_REG);
1209 		div = CCU_AHB1_CLK_DIV_RATIO(reg);
1210 		switch (reg & CCU_AHB1_CLK_SRC_SEL) {
1211 		case CCU_AHB1_CLK_SRC_SEL_LOSC:
1212 			parent = R40_CLK_LOSC;
1213 			break;
1214 		case CCU_AHB1_CLK_SRC_SEL_OSC24M:
1215 			parent = R40_CLK_HOSC;
1216 			break;
1217 		case CCU_AHB1_CLK_SRC_SEL_AXI:
1218 			parent = R40_CLK_AXI;
1219 			break;
1220 		case CCU_AHB1_CLK_SRC_SEL_PERIPH0:
1221 			parent = R40_CLK_PLL_PERIPH0;
1222 			div *= CCU_AHB1_PRE_DIV(reg);
1223 			break;
1224 		}
1225 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
1226 	case R40_CLK_APB2:
1227 		/* XXX Controlled by a MUX. */
1228 		return 24000000;
1229 	}
1230 
1231 	printf("%s: 0x%08x\n", __func__, idx);
1232 	return 0;
1233 }
1234 
1235 uint32_t
1236 sxiccmu_nop_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
1237 {
1238 	printf("%s: 0x%08x\n", __func__, idx);
1239 	return 0;
1240 }
1241 
1242 int
1243 sxiccmu_ccu_set_frequency(void *cookie, uint32_t *cells, uint32_t freq)
1244 {
1245 	struct sxiccmu_softc *sc = cookie;
1246 	uint32_t idx = cells[0];
1247 
1248 	return sc->sc_set_frequency(sc, idx, freq);
1249 }
1250 
1251 int
1252 sxiccmu_a10_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1253 {
1254 	struct sxiccmu_clock clock;
1255 	uint32_t parent, parent_freq;
1256 
1257 	switch (idx) {
1258 	case A10_CLK_MMC0:
1259 	case A10_CLK_MMC1:
1260 	case A10_CLK_MMC2:
1261 	case A10_CLK_MMC3:
1262 		clock.sc_iot = sc->sc_iot;
1263 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
1264 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
1265 		parent = A10_CLK_PLL_PERIPH;
1266 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
1267 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
1268 	}
1269 
1270 	printf("%s: 0x%08x\n", __func__, idx);
1271 	return -1;
1272 }
1273 
1274 int
1275 sxiccmu_a23_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1276 {
1277 	struct sxiccmu_clock clock;
1278 	uint32_t parent, parent_freq;
1279 
1280 	switch (idx) {
1281 	case A23_CLK_MMC0:
1282 	case A23_CLK_MMC1:
1283 	case A23_CLK_MMC2:
1284 		clock.sc_iot = sc->sc_iot;
1285 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
1286 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
1287 		parent = A23_CLK_PLL_PERIPH;
1288 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
1289 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
1290 	}
1291 
1292 	printf("%s: 0x%08x\n", __func__, idx);
1293 	return -1;
1294 }
1295 
1296 int
1297 sxiccmu_a64_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1298 {
1299 	struct sxiccmu_clock clock;
1300 	uint32_t parent, parent_freq;
1301 
1302 	switch (idx) {
1303 	case A64_CLK_MMC0:
1304 	case A64_CLK_MMC1:
1305 	case A64_CLK_MMC2:
1306 		clock.sc_iot = sc->sc_iot;
1307 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
1308 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
1309 		parent = A64_CLK_PLL_PERIPH0_2X;
1310 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
1311 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
1312 	}
1313 
1314 	printf("%s: 0x%08x\n", __func__, idx);
1315 	return -1;
1316 }
1317 
1318 int
1319 sxiccmu_a80_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1320 {
1321 	struct sxiccmu_clock clock;
1322 	uint32_t parent, parent_freq;
1323 
1324 	switch (idx) {
1325 	case A80_CLK_MMC0:
1326 	case A80_CLK_MMC1:
1327 	case A80_CLK_MMC2:
1328 		clock.sc_iot = sc->sc_iot;
1329 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
1330 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
1331 		parent = A80_CLK_PLL_PERIPH0;
1332 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
1333 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
1334 	}
1335 
1336 	printf("%s: 0x%08x\n", __func__, idx);
1337 	return -1;
1338 }
1339 
1340 int
1341 sxiccmu_h3_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1342 {
1343 	struct sxiccmu_clock clock;
1344 	uint32_t parent, parent_freq;
1345 	uint32_t reg;
1346 	int k, n;
1347 	int error;
1348 
1349 	switch (idx) {
1350 	case H3_CLK_PLL_CPUX:
1351 		k = 1; n = 32;
1352 		while (k <= 4 && (24000000 * n * k) < freq)
1353 			k++;
1354 		while (n >= 1 && (24000000 * n * k) > freq)
1355 			n--;
1356 
1357 		reg = SXIREAD4(sc, H3_PLL_CPUX_CTRL_REG);
1358 		reg &= ~H3_PLL_CPUX_OUT_EXT_DIVP_MASK;
1359 		reg &= ~H3_PLL_CPUX_FACTOR_N_MASK;
1360 		reg &= ~H3_PLL_CPUX_FACTOR_K_MASK;
1361 		reg &= ~H3_PLL_CPUX_FACTOR_M_MASK;
1362 		reg |= ((n - 1) << H3_PLL_CPUX_FACTOR_N_SHIFT);
1363 		reg |= ((k - 1) << H3_PLL_CPUX_FACTOR_K_SHIFT);
1364 		SXIWRITE4(sc, H3_PLL_CPUX_CTRL_REG, reg);
1365 
1366 		/* Wait for PLL to lock. */
1367 		while ((SXIREAD4(sc, H3_PLL_CPUX_CTRL_REG) &
1368 		    H3_PLL_CPUX_LOCK) == 0)
1369 			delay(1);
1370 
1371 		return 0;
1372 	case H3_CLK_CPUX:
1373 		/* Switch to 24 MHz clock. */
1374 		reg = SXIREAD4(sc, H3_CPUX_AXI_CFG_REG);
1375 		reg &= ~H3_CPUX_CLK_SRC_SEL;
1376 		reg |= H3_CPUX_CLK_SRC_SEL_OSC24M;
1377 		SXIWRITE4(sc, H3_CPUX_AXI_CFG_REG, reg);
1378 
1379 		error = sxiccmu_h3_set_frequency(sc, H3_CLK_PLL_CPUX, freq);
1380 
1381 		/* Switch back to PLL. */
1382 		reg = SXIREAD4(sc, H3_CPUX_AXI_CFG_REG);
1383 		reg &= ~H3_CPUX_CLK_SRC_SEL;
1384 		reg |= H3_CPUX_CLK_SRC_SEL_PLL_CPUX;
1385 		SXIWRITE4(sc, H3_CPUX_AXI_CFG_REG, reg);
1386 		return error;
1387 	case H3_CLK_MMC0:
1388 	case H3_CLK_MMC1:
1389 	case H3_CLK_MMC2:
1390 		clock.sc_iot = sc->sc_iot;
1391 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
1392 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
1393 		parent = H3_CLK_PLL_PERIPH0;
1394 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
1395 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
1396 	}
1397 
1398 	printf("%s: 0x%08x\n", __func__, idx);
1399 	return -1;
1400 }
1401 
1402 int
1403 sxiccmu_r40_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1404 {
1405 	struct sxiccmu_clock clock;
1406 	uint32_t parent, parent_freq;
1407 
1408 	switch (idx) {
1409 	case R40_CLK_MMC0:
1410 	case R40_CLK_MMC1:
1411 	case R40_CLK_MMC2:
1412 	case R40_CLK_MMC3:
1413 		clock.sc_iot = sc->sc_iot;
1414 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
1415 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
1416 		parent = R40_CLK_PLL_PERIPH0_2X;
1417 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
1418 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
1419 	}
1420 
1421 	printf("%s: 0x%08x\n", __func__, idx);
1422 	return -1;
1423 }
1424 
1425 int
1426 sxiccmu_nop_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1427 {
1428 	printf("%s: 0x%08x\n", __func__, idx);
1429 	return -1;
1430 }
1431 
1432 void
1433 sxiccmu_ccu_enable(void *cookie, uint32_t *cells, int on)
1434 {
1435 	struct sxiccmu_softc *sc = cookie;
1436 	uint32_t idx = cells[0];
1437 	int reg, bit;
1438 
1439 	clock_enable_all(sc->sc_node);
1440 
1441 	if (idx >= sc->sc_ngates ||
1442 	    (sc->sc_gates[idx].reg == 0 && sc->sc_gates[idx].bit == 0)) {
1443 		printf("%s: 0x%08x\n", __func__, cells[0]);
1444 		return;
1445 	}
1446 
1447 	reg = sc->sc_gates[idx].reg;
1448 	bit = sc->sc_gates[idx].bit;
1449 
1450 	if (on)
1451 		SXISET4(sc, reg, (1U << bit));
1452 	else
1453 		SXICLR4(sc, reg, (1U << bit));
1454 }
1455 
1456 void
1457 sxiccmu_ccu_reset(void *cookie, uint32_t *cells, int assert)
1458 {
1459 	struct sxiccmu_softc *sc = cookie;
1460 	uint32_t idx = cells[0];
1461 	int reg, bit;
1462 
1463 	reset_deassert_all(sc->sc_node);
1464 
1465 	if (idx >= sc->sc_nresets ||
1466 	    (sc->sc_resets[idx].reg == 0 && sc->sc_gates[idx].bit == 0)) {
1467 		printf("%s: 0x%08x\n", __func__, cells[0]);
1468 		return;
1469 	}
1470 
1471 	reg = sc->sc_resets[idx].reg;
1472 	bit = sc->sc_resets[idx].bit;
1473 
1474 	if (assert)
1475 		SXICLR4(sc, reg, (1U << bit));
1476 	else
1477 		SXISET4(sc, reg, (1U << bit));
1478 }
1479