xref: /openbsd-src/sys/dev/fdt/sxiccmu.c (revision 95c4b0b5bb79e30a3d8a10bdfa2e6347d4e23579)
1*95c4b0b5Skevlo /*	$OpenBSD: sxiccmu.c,v 1.38 2024/03/07 01:04:16 kevlo Exp $	*/
20ea1c705Spatrick /*
30ea1c705Spatrick  * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
40ea1c705Spatrick  * Copyright (c) 2013 Artturi Alm
5d526c0edSkettenis  * Copyright (c) 2016,2017 Mark Kettenis <kettenis@openbsd.org>
60ea1c705Spatrick  *
70ea1c705Spatrick  * Permission to use, copy, modify, and distribute this software for any
80ea1c705Spatrick  * purpose with or without fee is hereby granted, provided that the above
90ea1c705Spatrick  * copyright notice and this permission notice appear in all copies.
100ea1c705Spatrick  *
110ea1c705Spatrick  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
120ea1c705Spatrick  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
130ea1c705Spatrick  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
140ea1c705Spatrick  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
150ea1c705Spatrick  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
160ea1c705Spatrick  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
170ea1c705Spatrick  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
180ea1c705Spatrick  */
190ea1c705Spatrick 
200ea1c705Spatrick #include <sys/param.h>
210ea1c705Spatrick #include <sys/systm.h>
220ea1c705Spatrick #include <sys/kernel.h>
230ea1c705Spatrick #include <sys/malloc.h>
240ea1c705Spatrick #include <sys/time.h>
250ea1c705Spatrick #include <sys/device.h>
260ea1c705Spatrick 
270ea1c705Spatrick #include <machine/bus.h>
280ea1c705Spatrick #include <machine/fdt.h>
290ea1c705Spatrick #include <machine/intr.h>
300ea1c705Spatrick 
310ea1c705Spatrick #include <dev/fdt/sunxireg.h>
320ea1c705Spatrick 
330ea1c705Spatrick #include <dev/ofw/openfirm.h>
340ea1c705Spatrick #include <dev/ofw/ofw_clock.h>
3529e54e85Skettenis #include <dev/ofw/ofw_misc.h>
360ea1c705Spatrick #include <dev/ofw/fdt.h>
370ea1c705Spatrick 
3829e54e85Skettenis /* R40 */
3929e54e85Skettenis #define R40_GMAC_CLK_REG		0x0164
4029e54e85Skettenis 
410ea1c705Spatrick #ifdef DEBUG_CCMU
420ea1c705Spatrick #define DPRINTF(x)	do { printf x; } while (0)
430ea1c705Spatrick #else
440ea1c705Spatrick #define DPRINTF(x)
450ea1c705Spatrick #endif
460ea1c705Spatrick 
470ea1c705Spatrick struct sxiccmu_ccu_bit {
480ea1c705Spatrick 	uint16_t reg;
490ea1c705Spatrick 	uint8_t bit;
500ea1c705Spatrick 	uint8_t parent;
510ea1c705Spatrick };
520ea1c705Spatrick 
530ea1c705Spatrick #include "sxiccmu_clocks.h"
540ea1c705Spatrick 
550ea1c705Spatrick struct sxiccmu_softc {
560ea1c705Spatrick 	struct device		sc_dev;
570ea1c705Spatrick 	bus_space_tag_t		sc_iot;
580ea1c705Spatrick 	bus_space_handle_t	sc_ioh;
59b5fbf381Skettenis 	int			sc_node;
600ea1c705Spatrick 
6137c734d3Snaddy 	const struct sxiccmu_ccu_bit *sc_gates;
620ea1c705Spatrick 	int			sc_ngates;
630ea1c705Spatrick 	struct clock_device	sc_cd;
640ea1c705Spatrick 
6537c734d3Snaddy 	const struct sxiccmu_ccu_bit *sc_resets;
660ea1c705Spatrick 	int			sc_nresets;
670ea1c705Spatrick 	struct reset_device	sc_rd;
680ea1c705Spatrick 
690ea1c705Spatrick 	uint32_t		(*sc_get_frequency)(struct sxiccmu_softc *,
700ea1c705Spatrick 				    uint32_t);
710ea1c705Spatrick 	int			(*sc_set_frequency)(struct sxiccmu_softc *,
720ea1c705Spatrick 				    uint32_t, uint32_t);
730ea1c705Spatrick };
740ea1c705Spatrick 
750ea1c705Spatrick int	sxiccmu_match(struct device *, void *, void *);
760ea1c705Spatrick void	sxiccmu_attach(struct device *, struct device *, void *);
770ea1c705Spatrick 
789fdf0c62Smpi const struct cfattach	sxiccmu_ca = {
790ea1c705Spatrick 	sizeof (struct sxiccmu_softc), sxiccmu_match, sxiccmu_attach
800ea1c705Spatrick };
810ea1c705Spatrick 
820ea1c705Spatrick struct cfdriver sxiccmu_cd = {
830ea1c705Spatrick 	NULL, "sxiccmu", DV_DULL
840ea1c705Spatrick };
850ea1c705Spatrick 
864e7b86a5Skettenis void sxiccmu_attach_clock(struct sxiccmu_softc *, int, int);
870ea1c705Spatrick 
880ea1c705Spatrick uint32_t sxiccmu_ccu_get_frequency(void *, uint32_t *);
890ea1c705Spatrick int	sxiccmu_ccu_set_frequency(void *, uint32_t *, uint32_t);
900ea1c705Spatrick void	sxiccmu_ccu_enable(void *, uint32_t *, int);
910ea1c705Spatrick void	sxiccmu_ccu_reset(void *, uint32_t *, int);
920ea1c705Spatrick 
93e6e86968Skettenis uint32_t sxiccmu_a10_get_frequency(struct sxiccmu_softc *, uint32_t);
94e6e86968Skettenis int	sxiccmu_a10_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t);
95199786d9Skettenis uint32_t sxiccmu_a10s_get_frequency(struct sxiccmu_softc *, uint32_t);
96199786d9Skettenis int	sxiccmu_a10s_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t);
97f0a8b882Skevlo uint32_t sxiccmu_a23_get_frequency(struct sxiccmu_softc *, uint32_t);
98f0a8b882Skevlo int	sxiccmu_a23_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t);
990ea1c705Spatrick uint32_t sxiccmu_a64_get_frequency(struct sxiccmu_softc *, uint32_t);
1000ea1c705Spatrick int	sxiccmu_a64_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t);
101d526c0edSkettenis uint32_t sxiccmu_a80_get_frequency(struct sxiccmu_softc *, uint32_t);
102d526c0edSkettenis int	sxiccmu_a80_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t);
1034e48f70dSkettenis uint32_t sxiccmu_d1_get_frequency(struct sxiccmu_softc *, uint32_t);
1044e48f70dSkettenis int	sxiccmu_d1_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t);
1050ea1c705Spatrick uint32_t sxiccmu_h3_get_frequency(struct sxiccmu_softc *, uint32_t);
1060ea1c705Spatrick int	sxiccmu_h3_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t);
107322e71d8Skettenis uint32_t sxiccmu_h3_r_get_frequency(struct sxiccmu_softc *, uint32_t);
1088b22851bSkettenis uint32_t sxiccmu_h6_get_frequency(struct sxiccmu_softc *, uint32_t);
1098b22851bSkettenis int	sxiccmu_h6_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t);
1108b22851bSkettenis uint32_t sxiccmu_h6_r_get_frequency(struct sxiccmu_softc *, uint32_t);
11122652d99Suaa uint32_t sxiccmu_h616_get_frequency(struct sxiccmu_softc *, uint32_t);
11222652d99Suaa int	sxiccmu_h616_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t);
11322652d99Suaa uint32_t sxiccmu_h616_r_get_frequency(struct sxiccmu_softc *, uint32_t);
114a6d148daSkettenis uint32_t sxiccmu_r40_get_frequency(struct sxiccmu_softc *, uint32_t);
115a6d148daSkettenis int	sxiccmu_r40_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t);
1163fb3ba8fSkettenis uint32_t sxiccmu_v3s_get_frequency(struct sxiccmu_softc *, uint32_t);
1173fb3ba8fSkettenis int	sxiccmu_v3s_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t);
1182c064ff8Skettenis uint32_t sxiccmu_nop_get_frequency(struct sxiccmu_softc *, uint32_t);
1192c064ff8Skettenis int	sxiccmu_nop_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t);
1200ea1c705Spatrick 
1210ea1c705Spatrick int
sxiccmu_match(struct device * parent,void * match,void * aux)1220ea1c705Spatrick sxiccmu_match(struct device *parent, void *match, void *aux)
1230ea1c705Spatrick {
1240ea1c705Spatrick 	struct fdt_attach_args *faa = aux;
1252c064ff8Skettenis 	int node = faa->fa_node;
1260ea1c705Spatrick 
1272c064ff8Skettenis 	if (node == OF_finddevice("/clocks")) {
1282c064ff8Skettenis 		node = OF_parent(node);
1290ea1c705Spatrick 
1300ea1c705Spatrick 		return (OF_is_compatible(node, "allwinner,sun4i-a10") ||
1310ea1c705Spatrick 		    OF_is_compatible(node, "allwinner,sun5i-a10s") ||
1320ea1c705Spatrick 		    OF_is_compatible(node, "allwinner,sun5i-r8") ||
1330ea1c705Spatrick 		    OF_is_compatible(node, "allwinner,sun7i-a20") ||
134f0a8b882Skevlo 		    OF_is_compatible(node, "allwinner,sun8i-a23") ||
135f0a8b882Skevlo 		    OF_is_compatible(node, "allwinner,sun8i-a33") ||
1360ea1c705Spatrick 		    OF_is_compatible(node, "allwinner,sun8i-h3") ||
1373fb3ba8fSkettenis 		    OF_is_compatible(node, "allwinner,sun8i-v3s") ||
1385c793bcfSkettenis 		    OF_is_compatible(node, "allwinner,sun9i-a80") ||
1395c793bcfSkettenis 		    OF_is_compatible(node, "allwinner,sun50i-a64") ||
1405c793bcfSkettenis 		    OF_is_compatible(node, "allwinner,sun50i-h5"));
1410ea1c705Spatrick 	}
1420ea1c705Spatrick 
1432c064ff8Skettenis 	return (OF_is_compatible(node, "allwinner,sun4i-a10-ccu") ||
144199786d9Skettenis 	    OF_is_compatible(node, "allwinner,sun5i-a10s-ccu") ||
145199786d9Skettenis 	    OF_is_compatible(node, "allwinner,sun5i-a13-ccu") ||
1462c064ff8Skettenis 	    OF_is_compatible(node, "allwinner,sun7i-a20-ccu") ||
147f0a8b882Skevlo 	    OF_is_compatible(node, "allwinner,sun8i-a23-ccu") ||
1484e7b86a5Skettenis 	    OF_is_compatible(node, "allwinner,sun8i-a23-prcm") ||
149f0a8b882Skevlo 	    OF_is_compatible(node, "allwinner,sun8i-a33-ccu") ||
1502c064ff8Skettenis 	    OF_is_compatible(node, "allwinner,sun8i-h3-ccu") ||
151322e71d8Skettenis 	    OF_is_compatible(node, "allwinner,sun8i-h3-r-ccu") ||
152a6d148daSkettenis 	    OF_is_compatible(node, "allwinner,sun8i-r40-ccu") ||
1533fb3ba8fSkettenis 	    OF_is_compatible(node, "allwinner,sun8i-v3s-ccu") ||
1542c064ff8Skettenis 	    OF_is_compatible(node, "allwinner,sun9i-a80-ccu") ||
1552c064ff8Skettenis 	    OF_is_compatible(node, "allwinner,sun9i-a80-usb-clks") ||
1562c064ff8Skettenis 	    OF_is_compatible(node, "allwinner,sun9i-a80-mmc-config-clk") ||
1574e48f70dSkettenis 	    OF_is_compatible(node, "allwinner,sun20i-d1-ccu") ||
1582c064ff8Skettenis 	    OF_is_compatible(node, "allwinner,sun50i-a64-ccu") ||
15945fbe8fbSkettenis 	    OF_is_compatible(node, "allwinner,sun50i-a64-r-ccu") ||
1608b22851bSkettenis 	    OF_is_compatible(node, "allwinner,sun50i-h5-ccu") ||
1618b22851bSkettenis 	    OF_is_compatible(node, "allwinner,sun50i-h6-ccu") ||
16222652d99Suaa 	    OF_is_compatible(node, "allwinner,sun50i-h6-r-ccu") ||
16322652d99Suaa 	    OF_is_compatible(node, "allwinner,sun50i-h616-ccu") ||
16422652d99Suaa 	    OF_is_compatible(node, "allwinner,sun50i-h616-r-ccu"));
1650ea1c705Spatrick }
1660ea1c705Spatrick 
1670ea1c705Spatrick void
sxiccmu_attach(struct device * parent,struct device * self,void * aux)1680ea1c705Spatrick sxiccmu_attach(struct device *parent, struct device *self, void *aux)
1690ea1c705Spatrick {
1700ea1c705Spatrick 	struct sxiccmu_softc *sc = (struct sxiccmu_softc *)self;
1710ea1c705Spatrick 	struct fdt_attach_args *faa = aux;
1722c064ff8Skettenis 	int node = faa->fa_node;
1730ea1c705Spatrick 
174b5fbf381Skettenis 	sc->sc_node = faa->fa_node;
1750ea1c705Spatrick 	sc->sc_iot = faa->fa_iot;
1760ea1c705Spatrick 	if (faa->fa_nreg > 0 && bus_space_map(sc->sc_iot,
1770ea1c705Spatrick 	    faa->fa_reg[0].addr, faa->fa_reg[0].size, 0, &sc->sc_ioh))
1780ea1c705Spatrick 		panic("%s: bus_space_map failed!", __func__);
1790ea1c705Spatrick 
18029e54e85Skettenis 	/* On the R40, the GMAC needs to poke at one of our registers. */
18129e54e85Skettenis 	if (OF_is_compatible(node, "allwinner,sun8i-r40-ccu")) {
18229e54e85Skettenis 		bus_space_handle_t ioh;
18329e54e85Skettenis 
18429e54e85Skettenis 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
18529e54e85Skettenis 		    R40_GMAC_CLK_REG, 4, &ioh);
18629e54e85Skettenis 		regmap_register(faa->fa_node, sc->sc_iot, ioh, 4);
18729e54e85Skettenis 	}
18829e54e85Skettenis 
1890ea1c705Spatrick 	printf("\n");
1900ea1c705Spatrick 
1912c064ff8Skettenis 	if (OF_is_compatible(node, "allwinner,sun4i-a10-ccu") ||
1922c064ff8Skettenis 	    OF_is_compatible(node, "allwinner,sun7i-a20-ccu")) {
193e6e86968Skettenis 		KASSERT(faa->fa_nreg > 0);
194e6e86968Skettenis 		sc->sc_gates = sun4i_a10_gates;
195e6e86968Skettenis 		sc->sc_ngates = nitems(sun4i_a10_gates);
196e6e86968Skettenis 		sc->sc_resets = sun4i_a10_resets;
197e6e86968Skettenis 		sc->sc_nresets = nitems(sun4i_a10_resets);
198e6e86968Skettenis 		sc->sc_get_frequency = sxiccmu_a10_get_frequency;
199e6e86968Skettenis 		sc->sc_set_frequency = sxiccmu_a10_set_frequency;
200199786d9Skettenis 	} else if (OF_is_compatible(node, "allwinner,sun5i-a10s-ccu")) {
201199786d9Skettenis 		KASSERT(faa->fa_nreg > 0);
202199786d9Skettenis 		sc->sc_gates = sun5i_a10s_gates;
203199786d9Skettenis 		sc->sc_ngates = nitems(sun5i_a10s_gates);
204199786d9Skettenis 		sc->sc_resets = sun5i_a10s_resets;
205199786d9Skettenis 		sc->sc_nresets = nitems(sun5i_a10s_resets);
206199786d9Skettenis 		sc->sc_get_frequency = sxiccmu_a10s_get_frequency;
207199786d9Skettenis 		sc->sc_set_frequency = sxiccmu_a10s_set_frequency;
208f0a8b882Skevlo 	} else if (OF_is_compatible(node, "allwinner,sun8i-a23-ccu") ||
209f0a8b882Skevlo 	    OF_is_compatible(node, "allwinner,sun8i-a33-ccu")) {
210f0a8b882Skevlo 		KASSERT(faa->fa_nreg > 0);
211f0a8b882Skevlo 		sc->sc_gates = sun8i_a23_gates;
212f0a8b882Skevlo 		sc->sc_ngates = nitems(sun8i_a23_gates);
213f0a8b882Skevlo 		sc->sc_resets = sun8i_a23_resets;
214f0a8b882Skevlo 		sc->sc_nresets = nitems(sun8i_a23_resets);
215f0a8b882Skevlo 		sc->sc_get_frequency = sxiccmu_a23_get_frequency;
216f0a8b882Skevlo 		sc->sc_set_frequency = sxiccmu_a23_set_frequency;
2172c064ff8Skettenis 	} else if (OF_is_compatible(node, "allwinner,sun8i-h3-ccu") ||
2182c064ff8Skettenis 	    OF_is_compatible(node, "allwinner,sun50i-h5-ccu")) {
2190ea1c705Spatrick 		KASSERT(faa->fa_nreg > 0);
2200ea1c705Spatrick 		sc->sc_gates = sun8i_h3_gates;
2210ea1c705Spatrick 		sc->sc_ngates = nitems(sun8i_h3_gates);
2220ea1c705Spatrick 		sc->sc_resets = sun8i_h3_resets;
2230ea1c705Spatrick 		sc->sc_nresets = nitems(sun8i_h3_resets);
2240ea1c705Spatrick 		sc->sc_get_frequency = sxiccmu_h3_get_frequency;
2250ea1c705Spatrick 		sc->sc_set_frequency = sxiccmu_h3_set_frequency;
22645fbe8fbSkettenis 	} else if (OF_is_compatible(node, "allwinner,sun8i-h3-r-ccu") ||
22745fbe8fbSkettenis 	    OF_is_compatible(node, "allwinner,sun50i-a64-r-ccu")) {
228322e71d8Skettenis 		KASSERT(faa->fa_nreg > 0);
229322e71d8Skettenis 		sc->sc_gates = sun8i_h3_r_gates;
230322e71d8Skettenis 		sc->sc_ngates = nitems(sun8i_h3_r_gates);
231322e71d8Skettenis 		sc->sc_resets = sun8i_h3_r_resets;
232322e71d8Skettenis 		sc->sc_nresets = nitems(sun8i_h3_r_resets);
233322e71d8Skettenis 		sc->sc_get_frequency = sxiccmu_h3_r_get_frequency;
234322e71d8Skettenis 		sc->sc_set_frequency = sxiccmu_nop_set_frequency;
235a6d148daSkettenis 	} else if (OF_is_compatible(node, "allwinner,sun8i-r40-ccu")) {
236a6d148daSkettenis 		KASSERT(faa->fa_nreg > 0);
237a6d148daSkettenis 		sc->sc_gates = sun8i_r40_gates;
238a6d148daSkettenis 		sc->sc_ngates = nitems(sun8i_r40_gates);
239a6d148daSkettenis 		sc->sc_resets = sun8i_r40_resets;
240a6d148daSkettenis 		sc->sc_nresets = nitems(sun8i_r40_resets);
241a6d148daSkettenis 		sc->sc_get_frequency = sxiccmu_r40_get_frequency;
242a6d148daSkettenis 		sc->sc_set_frequency = sxiccmu_r40_set_frequency;
2433fb3ba8fSkettenis 	} else if (OF_is_compatible(node, "allwinner,sun8i-v3s-ccu")) {
2443fb3ba8fSkettenis 		KASSERT(faa->fa_nreg > 0);
2453fb3ba8fSkettenis 		sc->sc_gates = sun8i_v3s_gates;
2463fb3ba8fSkettenis 		sc->sc_ngates = nitems(sun8i_v3s_gates);
2473fb3ba8fSkettenis 		sc->sc_resets = sun8i_v3s_resets;
2483fb3ba8fSkettenis 		sc->sc_nresets = nitems(sun8i_v3s_resets);
2493fb3ba8fSkettenis 		sc->sc_get_frequency = sxiccmu_v3s_get_frequency;
2503fb3ba8fSkettenis 		sc->sc_set_frequency = sxiccmu_v3s_set_frequency;
2512c064ff8Skettenis 	} else if (OF_is_compatible(node, "allwinner,sun9i-a80-ccu")) {
252d526c0edSkettenis 		KASSERT(faa->fa_nreg > 0);
253d526c0edSkettenis 		sc->sc_gates = sun9i_a80_gates;
254d526c0edSkettenis 		sc->sc_ngates = nitems(sun9i_a80_gates);
255d526c0edSkettenis 		sc->sc_resets = sun9i_a80_resets;
256d526c0edSkettenis 		sc->sc_nresets = nitems(sun9i_a80_resets);
257d526c0edSkettenis 		sc->sc_get_frequency = sxiccmu_a80_get_frequency;
258d526c0edSkettenis 		sc->sc_set_frequency = sxiccmu_a80_set_frequency;
2592c064ff8Skettenis 	} else if (OF_is_compatible(node, "allwinner,sun9i-a80-usb-clks")) {
2602c064ff8Skettenis 		KASSERT(faa->fa_nreg > 0);
2612c064ff8Skettenis 		sc->sc_gates = sun9i_a80_usb_gates;
2622c064ff8Skettenis 		sc->sc_ngates = nitems(sun9i_a80_usb_gates);
2632c064ff8Skettenis 		sc->sc_resets = sun9i_a80_usb_resets;
2642c064ff8Skettenis 		sc->sc_nresets = nitems(sun9i_a80_usb_resets);
2652c064ff8Skettenis 		sc->sc_get_frequency = sxiccmu_nop_get_frequency;
2662c064ff8Skettenis 		sc->sc_set_frequency = sxiccmu_nop_set_frequency;
2672c064ff8Skettenis 	} else if (OF_is_compatible(node, "allwinner,sun9i-a80-mmc-config-clk")) {
2682c064ff8Skettenis 		KASSERT(faa->fa_nreg > 0);
2692c064ff8Skettenis 		sc->sc_gates = sun9i_a80_mmc_gates;
2702c064ff8Skettenis 		sc->sc_ngates = nitems(sun9i_a80_mmc_gates);
2712c064ff8Skettenis 		sc->sc_resets = sun9i_a80_mmc_resets;
2722c064ff8Skettenis 		sc->sc_nresets = nitems(sun9i_a80_mmc_resets);
2732c064ff8Skettenis 		sc->sc_get_frequency = sxiccmu_nop_get_frequency;
2742c064ff8Skettenis 		sc->sc_set_frequency = sxiccmu_nop_set_frequency;
2754e48f70dSkettenis 	} else if (OF_is_compatible(node, "allwinner,sun20i-d1-ccu")) {
2764e48f70dSkettenis 		KASSERT(faa->fa_nreg > 0);
2774e48f70dSkettenis 		sc->sc_gates = sun20i_d1_gates;
2784e48f70dSkettenis 		sc->sc_ngates = nitems(sun20i_d1_gates);
2794e48f70dSkettenis 		sc->sc_resets = sun20i_d1_resets;
2804e48f70dSkettenis 		sc->sc_nresets = nitems(sun20i_d1_resets);
2814e48f70dSkettenis 		sc->sc_get_frequency = sxiccmu_d1_get_frequency;
2824e48f70dSkettenis 		sc->sc_set_frequency = sxiccmu_d1_set_frequency;
2832c064ff8Skettenis 	} else if (OF_is_compatible(node, "allwinner,sun50i-a64-ccu")) {
284d526c0edSkettenis 		KASSERT(faa->fa_nreg > 0);
285d526c0edSkettenis 		sc->sc_gates = sun50i_a64_gates;
286d526c0edSkettenis 		sc->sc_ngates = nitems(sun50i_a64_gates);
287d526c0edSkettenis 		sc->sc_resets = sun50i_a64_resets;
288d526c0edSkettenis 		sc->sc_nresets = nitems(sun50i_a64_resets);
289d526c0edSkettenis 		sc->sc_get_frequency = sxiccmu_a64_get_frequency;
290d526c0edSkettenis 		sc->sc_set_frequency = sxiccmu_a64_set_frequency;
2918b22851bSkettenis 	} else if (OF_is_compatible(node, "allwinner,sun50i-h6-ccu")) {
2928b22851bSkettenis 		KASSERT(faa->fa_nreg > 0);
2938b22851bSkettenis 		sc->sc_gates = sun50i_h6_gates;
2948b22851bSkettenis 		sc->sc_ngates = nitems(sun50i_h6_gates);
2958b22851bSkettenis 		sc->sc_resets = sun50i_h6_resets;
2968b22851bSkettenis 		sc->sc_nresets = nitems(sun50i_h6_resets);
2978b22851bSkettenis 		sc->sc_get_frequency = sxiccmu_h6_get_frequency;
2988b22851bSkettenis 		sc->sc_set_frequency = sxiccmu_h6_set_frequency;
2998b22851bSkettenis 	} else if (OF_is_compatible(node, "allwinner,sun50i-h6-r-ccu")) {
3008b22851bSkettenis 		KASSERT(faa->fa_nreg > 0);
3018b22851bSkettenis 		sc->sc_gates = sun50i_h6_r_gates;
3028b22851bSkettenis 		sc->sc_ngates = nitems(sun50i_h6_r_gates);
3038b22851bSkettenis 		sc->sc_resets = sun50i_h6_r_resets;
3048b22851bSkettenis 		sc->sc_nresets = nitems(sun50i_h6_r_resets);
3058b22851bSkettenis 		sc->sc_get_frequency = sxiccmu_h6_r_get_frequency;
3068b22851bSkettenis 		sc->sc_set_frequency = sxiccmu_nop_set_frequency;
30722652d99Suaa 	} else if (OF_is_compatible(node, "allwinner,sun50i-h616-ccu")) {
30822652d99Suaa 		KASSERT(faa->fa_nreg > 0);
30922652d99Suaa 		sc->sc_gates = sun50i_h616_gates;
31022652d99Suaa 		sc->sc_ngates = nitems(sun50i_h616_gates);
31122652d99Suaa 		sc->sc_resets = sun50i_h616_resets;
31222652d99Suaa 		sc->sc_nresets = nitems(sun50i_h616_resets);
31322652d99Suaa 		sc->sc_get_frequency = sxiccmu_h616_get_frequency;
31422652d99Suaa 		sc->sc_set_frequency = sxiccmu_h616_set_frequency;
31522652d99Suaa 	} else if (OF_is_compatible(node, "allwinner,sun50i-h616-r-ccu")) {
31622652d99Suaa 		KASSERT(faa->fa_nreg > 0);
31722652d99Suaa 		sc->sc_gates = sun50i_h616_r_gates;
31822652d99Suaa 		sc->sc_ngates = nitems(sun50i_h616_r_gates);
31922652d99Suaa 		sc->sc_resets = sun50i_h616_r_resets;
32022652d99Suaa 		sc->sc_nresets = nitems(sun50i_h616_r_resets);
32122652d99Suaa 		sc->sc_get_frequency = sxiccmu_h616_r_get_frequency;
32222652d99Suaa 		sc->sc_set_frequency = sxiccmu_nop_set_frequency;
3230ea1c705Spatrick 	} else {
3242c064ff8Skettenis 		for (node = OF_child(node); node; node = OF_peer(node))
3254e7b86a5Skettenis 			sxiccmu_attach_clock(sc, node, faa->fa_nreg);
3260ea1c705Spatrick 	}
3270ea1c705Spatrick 
3280ea1c705Spatrick 	if (sc->sc_gates) {
329b5fbf381Skettenis 		sc->sc_cd.cd_node = sc->sc_node;
3300ea1c705Spatrick 		sc->sc_cd.cd_cookie = sc;
3310ea1c705Spatrick 		sc->sc_cd.cd_get_frequency = sxiccmu_ccu_get_frequency;
3320ea1c705Spatrick 		sc->sc_cd.cd_set_frequency = sxiccmu_ccu_set_frequency;
3330ea1c705Spatrick 		sc->sc_cd.cd_enable = sxiccmu_ccu_enable;
3340ea1c705Spatrick 		clock_register(&sc->sc_cd);
3350ea1c705Spatrick 	}
3360ea1c705Spatrick 
3370ea1c705Spatrick 	if (sc->sc_resets) {
338b5fbf381Skettenis 		sc->sc_rd.rd_node = sc->sc_node;
3390ea1c705Spatrick 		sc->sc_rd.rd_cookie = sc;
3400ea1c705Spatrick 		sc->sc_rd.rd_reset = sxiccmu_ccu_reset;
3410ea1c705Spatrick 		reset_register(&sc->sc_rd);
3420ea1c705Spatrick 	}
3430ea1c705Spatrick }
3440ea1c705Spatrick 
3450ea1c705Spatrick /*
346b5fbf381Skettenis  * Classic device trees for the Allwinner SoCs have basically a clock
347b5fbf381Skettenis  * node per register of the clock control unit.  Attaching a separate
348b5fbf381Skettenis  * driver to each of them would be crazy, so we handle them here.
3490ea1c705Spatrick  */
3500ea1c705Spatrick 
3510ea1c705Spatrick struct sxiccmu_clock {
3520ea1c705Spatrick 	int sc_node;
3530ea1c705Spatrick 	bus_space_tag_t sc_iot;
3540ea1c705Spatrick 	bus_space_handle_t sc_ioh;
3550ea1c705Spatrick 
3560ea1c705Spatrick 	struct clock_device sc_cd;
3570ea1c705Spatrick 	struct reset_device sc_rd;
3580ea1c705Spatrick };
3590ea1c705Spatrick 
3600ea1c705Spatrick struct sxiccmu_device {
3610ea1c705Spatrick 	const char *compat;
3620ea1c705Spatrick 	uint32_t (*get_frequency)(void *, uint32_t *);
3630ea1c705Spatrick 	int	(*set_frequency)(void *, uint32_t *, uint32_t);
3640ea1c705Spatrick 	void	(*enable)(void *, uint32_t *, int);
3650ea1c705Spatrick 	void	(*reset)(void *, uint32_t *, int);
3664e7b86a5Skettenis 	bus_size_t offset;
3670ea1c705Spatrick };
3680ea1c705Spatrick 
3690ea1c705Spatrick uint32_t sxiccmu_gen_get_frequency(void *, uint32_t *);
3700ea1c705Spatrick uint32_t sxiccmu_osc_get_frequency(void *, uint32_t *);
3710ea1c705Spatrick uint32_t sxiccmu_pll6_get_frequency(void *, uint32_t *);
3720ea1c705Spatrick void	sxiccmu_pll6_enable(void *, uint32_t *, int);
3730ea1c705Spatrick uint32_t sxiccmu_apb1_get_frequency(void *, uint32_t *);
3745e83a44fSkettenis uint32_t sxiccmu_cpus_get_frequency(void *, uint32_t *);
3755e83a44fSkettenis uint32_t sxiccmu_apbs_get_frequency(void *, uint32_t *);
3760ea1c705Spatrick int	sxiccmu_gmac_set_frequency(void *, uint32_t *, uint32_t);
3770ea1c705Spatrick int	sxiccmu_mmc_set_frequency(void *, uint32_t *, uint32_t);
3780ea1c705Spatrick void	sxiccmu_mmc_enable(void *, uint32_t *, int);
3790ea1c705Spatrick void	sxiccmu_gate_enable(void *, uint32_t *, int);
3800ea1c705Spatrick void	sxiccmu_reset(void *, uint32_t *, int);
3810ea1c705Spatrick 
38237c734d3Snaddy const struct sxiccmu_device sxiccmu_devices[] = {
3830ea1c705Spatrick 	{
3840ea1c705Spatrick 		.compat = "allwinner,sun4i-a10-osc-clk",
3850ea1c705Spatrick 		.get_frequency = sxiccmu_osc_get_frequency,
3860ea1c705Spatrick 	},
3870ea1c705Spatrick 	{
3880ea1c705Spatrick 		.compat = "allwinner,sun4i-a10-pll6-clk",
3890ea1c705Spatrick 		.get_frequency = sxiccmu_pll6_get_frequency,
3900ea1c705Spatrick 		.enable = sxiccmu_pll6_enable
3910ea1c705Spatrick 	},
3920ea1c705Spatrick 	{
3930ea1c705Spatrick 		.compat = "allwinner,sun4i-a10-apb1-clk",
3940ea1c705Spatrick 		.get_frequency = sxiccmu_apb1_get_frequency,
3950ea1c705Spatrick 	},
3960ea1c705Spatrick 	{
3970ea1c705Spatrick 		.compat = "allwinner,sun4i-a10-ahb-gates-clk",
3980ea1c705Spatrick 		.get_frequency = sxiccmu_gen_get_frequency,
3990ea1c705Spatrick 		.enable = sxiccmu_gate_enable
4000ea1c705Spatrick 	},
4010ea1c705Spatrick 	{
4020ea1c705Spatrick 		.compat = "allwinner,sun4i-a10-apb0-gates-clk",
4030ea1c705Spatrick 		.get_frequency = sxiccmu_gen_get_frequency,
4040ea1c705Spatrick 		.enable = sxiccmu_gate_enable
4050ea1c705Spatrick 	},
4060ea1c705Spatrick 	{
4070ea1c705Spatrick 		.compat = "allwinner,sun4i-a10-apb1-gates-clk",
4080ea1c705Spatrick 		.get_frequency = sxiccmu_gen_get_frequency,
4090ea1c705Spatrick 		.enable = sxiccmu_gate_enable
4100ea1c705Spatrick 	},
4110ea1c705Spatrick 	{
4120ea1c705Spatrick 		.compat = "allwinner,sun4i-a10-mmc-clk",
4130ea1c705Spatrick 		.set_frequency = sxiccmu_mmc_set_frequency,
4140ea1c705Spatrick 		.enable = sxiccmu_mmc_enable
4150ea1c705Spatrick 	},
4160ea1c705Spatrick 	{
4170ea1c705Spatrick 		.compat = "allwinner,sun4i-a10-usb-clk",
4180ea1c705Spatrick 		.get_frequency = sxiccmu_gen_get_frequency,
4190ea1c705Spatrick 		.enable = sxiccmu_gate_enable,
4200ea1c705Spatrick 		.reset = sxiccmu_reset
4210ea1c705Spatrick 	},
4220ea1c705Spatrick 	{
4230ea1c705Spatrick 		.compat = "allwinner,sun5i-a10s-ahb-gates-clk",
4240ea1c705Spatrick 		.get_frequency = sxiccmu_gen_get_frequency,
4250ea1c705Spatrick 		.enable = sxiccmu_gate_enable
4260ea1c705Spatrick 	},
4270ea1c705Spatrick 	{
4280ea1c705Spatrick 		.compat = "allwinner,sun5i-a10s-apb0-gates-clk",
4290ea1c705Spatrick 		.get_frequency = sxiccmu_gen_get_frequency,
4300ea1c705Spatrick 		.enable = sxiccmu_gate_enable
4310ea1c705Spatrick 	},
4320ea1c705Spatrick 	{
4330ea1c705Spatrick 		.compat = "allwinner,sun5i-a10s-apb1-gates-clk",
4340ea1c705Spatrick 		.get_frequency = sxiccmu_gen_get_frequency,
4350ea1c705Spatrick 		.enable = sxiccmu_gate_enable
4360ea1c705Spatrick 	},
4370ea1c705Spatrick 	{
4380ea1c705Spatrick 		.compat = "allwinner,sun5i-a13-ahb-gates-clk",
4390ea1c705Spatrick 		.get_frequency = sxiccmu_gen_get_frequency,
4400ea1c705Spatrick 		.enable = sxiccmu_gate_enable
4410ea1c705Spatrick 	},
4420ea1c705Spatrick 	{
4430ea1c705Spatrick 		.compat = "allwinner,sun5i-a13-apb0-gates-clk",
4440ea1c705Spatrick 		.get_frequency = sxiccmu_gen_get_frequency,
4450ea1c705Spatrick 		.enable = sxiccmu_gate_enable
4460ea1c705Spatrick 	},
4470ea1c705Spatrick 	{
4480ea1c705Spatrick 		.compat = "allwinner,sun5i-a13-apb1-gates-clk",
4490ea1c705Spatrick 		.get_frequency = sxiccmu_gen_get_frequency,
4500ea1c705Spatrick 		.enable = sxiccmu_gate_enable
4510ea1c705Spatrick 	},
4520ea1c705Spatrick 	{
4530ea1c705Spatrick 		.compat = "allwinner,sun5i-a13-usb-clk",
4540ea1c705Spatrick 		.get_frequency = sxiccmu_gen_get_frequency,
4550ea1c705Spatrick 		.enable = sxiccmu_gate_enable,
4560ea1c705Spatrick 		.reset = sxiccmu_reset
4570ea1c705Spatrick 	},
4580ea1c705Spatrick 	{
4590ea1c705Spatrick 		.compat = "allwinner,sun6i-a31-ahb1-reset",
4600ea1c705Spatrick 		.reset = sxiccmu_reset
4610ea1c705Spatrick 	},
4620ea1c705Spatrick 	{
4630ea1c705Spatrick 		.compat = "allwinner,sun6i-a31-clock-reset",
4644e7b86a5Skettenis 		.reset = sxiccmu_reset,
4654e7b86a5Skettenis 		.offset = 0x00b0
4660ea1c705Spatrick 	},
4670ea1c705Spatrick 	{
4680ea1c705Spatrick 		.compat = "allwinner,sun7i-a20-ahb-gates-clk",
4690ea1c705Spatrick 		.get_frequency = sxiccmu_gen_get_frequency,
4700ea1c705Spatrick 		.enable = sxiccmu_gate_enable
4710ea1c705Spatrick 	},
4720ea1c705Spatrick 	{
4730ea1c705Spatrick 		.compat = "allwinner,sun7i-a20-apb0-gates-clk",
4740ea1c705Spatrick 		.get_frequency = sxiccmu_gen_get_frequency,
4750ea1c705Spatrick 		.enable = sxiccmu_gate_enable
4760ea1c705Spatrick 	},
4770ea1c705Spatrick 	{
4780ea1c705Spatrick 		.compat = "allwinner,sun7i-a20-apb1-gates-clk",
4790ea1c705Spatrick 		.get_frequency = sxiccmu_gen_get_frequency,
4800ea1c705Spatrick 		.enable = sxiccmu_gate_enable
4810ea1c705Spatrick 	},
4820ea1c705Spatrick 	{
4830ea1c705Spatrick 		.compat = "allwinner,sun7i-a20-gmac-clk",
4840ea1c705Spatrick 		.set_frequency = sxiccmu_gmac_set_frequency
4850ea1c705Spatrick 	},
4860ea1c705Spatrick 	{
4875e83a44fSkettenis 		.compat = "allwinner,sun8i-a23-apb0-clk",
4884e7b86a5Skettenis 		.get_frequency = sxiccmu_apbs_get_frequency,
4894e7b86a5Skettenis 		.offset = 0x000c
4905e83a44fSkettenis 	},
4915e83a44fSkettenis 	{
492f0a8b882Skevlo 		.compat = "allwinner,sun8i-a23-ahb1-gates-clk",
493f0a8b882Skevlo 		.get_frequency = sxiccmu_gen_get_frequency,
494f0a8b882Skevlo 		.enable = sxiccmu_gate_enable
495f0a8b882Skevlo 	},
496f0a8b882Skevlo 	{
497f0a8b882Skevlo 		.compat = "allwinner,sun8i-a23-apb0-gates-clk",
498f0a8b882Skevlo 		.get_frequency = sxiccmu_gen_get_frequency,
4994e7b86a5Skettenis 		.enable = sxiccmu_gate_enable,
5004e7b86a5Skettenis 		.offset = 0x0028
501f0a8b882Skevlo 	},
502f0a8b882Skevlo 	{
503f0a8b882Skevlo 		.compat = "allwinner,sun8i-a23-apb1-gates-clk",
504f0a8b882Skevlo 		.get_frequency = sxiccmu_gen_get_frequency,
505f0a8b882Skevlo 		.enable = sxiccmu_gate_enable
506f0a8b882Skevlo 	},
507f0a8b882Skevlo 	{
508f0a8b882Skevlo 		.compat = "allwinner,sun8i-a23-apb2-gates-clk",
509f0a8b882Skevlo 		.get_frequency = sxiccmu_gen_get_frequency,
510f0a8b882Skevlo 		.enable = sxiccmu_gate_enable
511f0a8b882Skevlo 	},
512f0a8b882Skevlo 	{
513f0a8b882Skevlo 		.compat = "allwinner,sun8i-a23-usb-clk",
514f0a8b882Skevlo 		.get_frequency = sxiccmu_gen_get_frequency,
515f0a8b882Skevlo 		.enable = sxiccmu_gate_enable,
516f0a8b882Skevlo 		.reset = sxiccmu_reset
517f0a8b882Skevlo 	},
518f0a8b882Skevlo 	{
5190ea1c705Spatrick 		.compat = "allwinner,sun8i-h3-apb0-gates-clk",
5200ea1c705Spatrick 		.get_frequency = sxiccmu_gen_get_frequency,
5210ea1c705Spatrick 		.enable = sxiccmu_gate_enable
5220ea1c705Spatrick 	},
5230ea1c705Spatrick 	{
5240ea1c705Spatrick 		.compat = "allwinner,sun9i-a80-apb1-clk",
5250ea1c705Spatrick 		.get_frequency = sxiccmu_apb1_get_frequency,
5260ea1c705Spatrick 	},
5270ea1c705Spatrick 	{
5280ea1c705Spatrick 		.compat = "allwinner,sun9i-a80-ahb0-gates-clk",
5290ea1c705Spatrick 		.get_frequency = sxiccmu_gen_get_frequency,
5300ea1c705Spatrick 		.enable = sxiccmu_gate_enable
5310ea1c705Spatrick 	},
5320ea1c705Spatrick 	{
5330ea1c705Spatrick 		.compat = "allwinner,sun9i-a80-ahb1-gates-clk",
5340ea1c705Spatrick 		.get_frequency = sxiccmu_gen_get_frequency,
5350ea1c705Spatrick 		.enable = sxiccmu_gate_enable
5360ea1c705Spatrick 	},
5370ea1c705Spatrick 	{
5380ea1c705Spatrick 		.compat = "allwinner,sun9i-a80-ahb2-gates-clk",
5390ea1c705Spatrick 		.get_frequency = sxiccmu_gen_get_frequency,
5400ea1c705Spatrick 		.enable = sxiccmu_gate_enable
5410ea1c705Spatrick 	},
5420ea1c705Spatrick 	{
5430ea1c705Spatrick 		.compat = "allwinner,sun9i-a80-apb0-gates-clk",
5440ea1c705Spatrick 		.get_frequency = sxiccmu_gen_get_frequency,
5450ea1c705Spatrick 		.enable = sxiccmu_gate_enable
5460ea1c705Spatrick 	},
5470ea1c705Spatrick 	{
5480ea1c705Spatrick 		.compat = "allwinner,sun9i-a80-apb1-gates-clk",
5490ea1c705Spatrick 		.get_frequency = sxiccmu_gen_get_frequency,
5500ea1c705Spatrick 		.enable = sxiccmu_gate_enable
5510ea1c705Spatrick 	},
5520ea1c705Spatrick 	{
5530ea1c705Spatrick 		.compat = "allwinner,sun9i-a80-apbs-gates-clk",
5540ea1c705Spatrick 		.get_frequency = sxiccmu_gen_get_frequency,
5550ea1c705Spatrick 		.enable = sxiccmu_gate_enable
5560ea1c705Spatrick 	},
5570ea1c705Spatrick 	{
5585e83a44fSkettenis 		.compat = "allwinner,sun9i-a80-cpus-clk",
5595e83a44fSkettenis 		.get_frequency = sxiccmu_cpus_get_frequency
5605e83a44fSkettenis 	},
5615e83a44fSkettenis 	{
5620ea1c705Spatrick 		.compat = "allwinner,sun9i-a80-mmc-clk",
5630ea1c705Spatrick 		.set_frequency = sxiccmu_mmc_set_frequency,
5640ea1c705Spatrick 		.enable = sxiccmu_mmc_enable
5650ea1c705Spatrick 	},
5660ea1c705Spatrick 	{
5670ea1c705Spatrick 		.compat = "allwinner,sun9i-a80-usb-mod-clk",
5680ea1c705Spatrick 		.get_frequency = sxiccmu_gen_get_frequency,
5690ea1c705Spatrick 		.enable = sxiccmu_gate_enable,
5700ea1c705Spatrick 		.reset = sxiccmu_reset
5710ea1c705Spatrick 	},
5720ea1c705Spatrick 	{
5730ea1c705Spatrick 		.compat = "allwinner,sun9i-a80-usb-phy-clk",
5740ea1c705Spatrick 		.get_frequency = sxiccmu_gen_get_frequency,
5750ea1c705Spatrick 		.enable = sxiccmu_gate_enable,
5760ea1c705Spatrick 		.reset = sxiccmu_reset
5770ea1c705Spatrick 	},
5780ea1c705Spatrick };
5790ea1c705Spatrick 
5800ea1c705Spatrick void
sxiccmu_attach_clock(struct sxiccmu_softc * sc,int node,int nreg)5814e7b86a5Skettenis sxiccmu_attach_clock(struct sxiccmu_softc *sc, int node, int nreg)
5820ea1c705Spatrick {
5830ea1c705Spatrick 	struct sxiccmu_clock *clock;
5840ea1c705Spatrick 	uint32_t reg[2];
5854e7b86a5Skettenis 	int i, error = ENODEV;
5860ea1c705Spatrick 
5870ea1c705Spatrick 	for (i = 0; i < nitems(sxiccmu_devices); i++)
5880ea1c705Spatrick 		if (OF_is_compatible(node, sxiccmu_devices[i].compat))
5890ea1c705Spatrick 			break;
5900ea1c705Spatrick 	if (i == nitems(sxiccmu_devices))
5910ea1c705Spatrick 		return;
5920ea1c705Spatrick 
5930ea1c705Spatrick 	clock = malloc(sizeof(*clock), M_DEVBUF, M_WAITOK);
5940ea1c705Spatrick 	clock->sc_node = node;
5950ea1c705Spatrick 
5960ea1c705Spatrick 	clock->sc_iot = sc->sc_iot;
5974e7b86a5Skettenis 	if (OF_getpropintarray(node, "reg", reg, sizeof(reg)) == sizeof(reg)) {
5984e7b86a5Skettenis 		error = bus_space_map(clock->sc_iot, reg[0], reg[1], 0,
5994e7b86a5Skettenis 		    &clock->sc_ioh);
6004e7b86a5Skettenis 	} else if (nreg > 0) {
6014e7b86a5Skettenis 		error = bus_space_subregion(clock->sc_iot, sc->sc_ioh,
6024e7b86a5Skettenis 		    sxiccmu_devices[i].offset, 4, &clock->sc_ioh);
6034e7b86a5Skettenis 	}
6044e7b86a5Skettenis 	if (error) {
6050ea1c705Spatrick 		printf("%s: can't map registers", sc->sc_dev.dv_xname);
6060ea1c705Spatrick 		free(clock, M_DEVBUF, sizeof(*clock));
6070ea1c705Spatrick 		return;
6080ea1c705Spatrick 	}
6090ea1c705Spatrick 
6100ea1c705Spatrick 	clock->sc_cd.cd_node = node;
6110ea1c705Spatrick 	clock->sc_cd.cd_cookie = clock;
6120ea1c705Spatrick 	clock->sc_cd.cd_get_frequency = sxiccmu_devices[i].get_frequency;
6130ea1c705Spatrick 	clock->sc_cd.cd_set_frequency = sxiccmu_devices[i].set_frequency;
6140ea1c705Spatrick 	clock->sc_cd.cd_enable = sxiccmu_devices[i].enable;
6150ea1c705Spatrick 	clock_register(&clock->sc_cd);
6160ea1c705Spatrick 
6170ea1c705Spatrick 	if (sxiccmu_devices[i].reset) {
6180ea1c705Spatrick 		clock->sc_rd.rd_node = node;
6190ea1c705Spatrick 		clock->sc_rd.rd_cookie = clock;
6200ea1c705Spatrick 		clock->sc_rd.rd_reset = sxiccmu_devices[i].reset;
6210ea1c705Spatrick 		reset_register(&clock->sc_rd);
6220ea1c705Spatrick 	}
6230ea1c705Spatrick }
6240ea1c705Spatrick 
6250ea1c705Spatrick /*
6260ea1c705Spatrick  * A "generic" function that simply gets the clock frequency from the
6270ea1c705Spatrick  * parent clock.  Useful for clock gating devices that don't scale
6280ea1c705Spatrick  * their clocks.
6290ea1c705Spatrick  */
6300ea1c705Spatrick uint32_t
sxiccmu_gen_get_frequency(void * cookie,uint32_t * cells)6310ea1c705Spatrick sxiccmu_gen_get_frequency(void *cookie, uint32_t *cells)
6320ea1c705Spatrick {
6330ea1c705Spatrick 	struct sxiccmu_clock *sc = cookie;
6340ea1c705Spatrick 
6350ea1c705Spatrick 	return clock_get_frequency(sc->sc_node, NULL);
6360ea1c705Spatrick }
6370ea1c705Spatrick 
6380ea1c705Spatrick uint32_t
sxiccmu_osc_get_frequency(void * cookie,uint32_t * cells)6390ea1c705Spatrick sxiccmu_osc_get_frequency(void *cookie, uint32_t *cells)
6400ea1c705Spatrick {
6410ea1c705Spatrick 	struct sxiccmu_clock *sc = cookie;
6420ea1c705Spatrick 
6430ea1c705Spatrick 	return OF_getpropint(sc->sc_node, "clock-frequency", 24000000);
6440ea1c705Spatrick }
6450ea1c705Spatrick 
6460ea1c705Spatrick #define CCU_PLL6_ENABLE			(1U << 31)
6470ea1c705Spatrick #define CCU_PLL6_BYPASS_EN		(1U << 30)
6480ea1c705Spatrick #define CCU_PLL6_SATA_CLK_EN		(1U << 14)
6490ea1c705Spatrick #define CCU_PLL6_FACTOR_N(x)		(((x) >> 8) & 0x1f)
6500ea1c705Spatrick #define CCU_PLL6_FACTOR_N_MASK		(0x1f << 8)
6510ea1c705Spatrick #define CCU_PLL6_FACTOR_N_SHIFT		8
6520ea1c705Spatrick #define CCU_PLL6_FACTOR_K(x)		(((x) >> 4) & 0x3)
6530ea1c705Spatrick #define CCU_PLL6_FACTOR_K_MASK		(0x3 << 4)
6540ea1c705Spatrick #define CCU_PLL6_FACTOR_K_SHIFT		4
6550ea1c705Spatrick #define CCU_PLL6_FACTOR_M(x)		(((x) >> 0) & 0x3)
6560ea1c705Spatrick #define CCU_PLL6_FACTOR_M_MASK		(0x3 << 0)
6570ea1c705Spatrick #define CCU_PLL6_FACTOR_M_SHIFT		0
6580ea1c705Spatrick 
6590ea1c705Spatrick uint32_t
sxiccmu_pll6_get_frequency(void * cookie,uint32_t * cells)6600ea1c705Spatrick sxiccmu_pll6_get_frequency(void *cookie, uint32_t *cells)
6610ea1c705Spatrick {
6620ea1c705Spatrick 	struct sxiccmu_clock *sc = cookie;
6630ea1c705Spatrick 	uint32_t reg, k, m, n, freq;
6640ea1c705Spatrick 	uint32_t idx = cells[0];
6650ea1c705Spatrick 
6660ea1c705Spatrick 	/* XXX Assume bypass is disabled. */
6670ea1c705Spatrick 	reg = SXIREAD4(sc, 0);
6680ea1c705Spatrick 	k = CCU_PLL6_FACTOR_K(reg) + 1;
6690ea1c705Spatrick 	m = CCU_PLL6_FACTOR_M(reg) + 1;
6700ea1c705Spatrick 	n = CCU_PLL6_FACTOR_N(reg);
6710ea1c705Spatrick 
6720ea1c705Spatrick 	freq = clock_get_frequency_idx(sc->sc_node, 0);
6730ea1c705Spatrick 	switch (idx) {
6740ea1c705Spatrick 	case 0:
6750ea1c705Spatrick 		return (freq * n * k) / m / 6;		/* pll6_sata */
6760ea1c705Spatrick 	case 1:
6770ea1c705Spatrick 		return (freq * n * k) / 2;		/* pll6_other */
6780ea1c705Spatrick 	case 2:
6790ea1c705Spatrick 		return (freq * n * k);			/* pll6 */
6800ea1c705Spatrick 	case 3:
6810ea1c705Spatrick 		return (freq * n * k) / 4;		/* pll6_div_4 */
6820ea1c705Spatrick 	}
6830ea1c705Spatrick 
6840ea1c705Spatrick 	return 0;
6850ea1c705Spatrick }
6860ea1c705Spatrick 
6870ea1c705Spatrick void
sxiccmu_pll6_enable(void * cookie,uint32_t * cells,int on)6880ea1c705Spatrick sxiccmu_pll6_enable(void *cookie, uint32_t *cells, int on)
6890ea1c705Spatrick {
6900ea1c705Spatrick 	struct sxiccmu_clock *sc = cookie;
6910ea1c705Spatrick 	uint32_t idx = cells[0];
6920ea1c705Spatrick 	uint32_t reg;
6930ea1c705Spatrick 
6940ea1c705Spatrick 	/*
6950ea1c705Spatrick 	 * Since this clock has several outputs, we never turn it off.
6960ea1c705Spatrick 	 */
6970ea1c705Spatrick 
6980ea1c705Spatrick 	reg = SXIREAD4(sc, 0);
6990ea1c705Spatrick 	switch (idx) {
7000ea1c705Spatrick 	case 0:			/* pll6_sata */
7010ea1c705Spatrick 		if (on)
7020ea1c705Spatrick 			reg |= CCU_PLL6_SATA_CLK_EN;
7030ea1c705Spatrick 		else
7040ea1c705Spatrick 			reg &= ~CCU_PLL6_SATA_CLK_EN;
7050ea1c705Spatrick 		/* FALLTHROUGH */
7060ea1c705Spatrick 	case 1:			/* pll6_other */
7070ea1c705Spatrick 	case 2:			/* pll6 */
7080ea1c705Spatrick 	case 3:			/* pll6_div_4 */
7090ea1c705Spatrick 		if (on)
7100ea1c705Spatrick 			reg |= CCU_PLL6_ENABLE;
7110ea1c705Spatrick 	}
7120ea1c705Spatrick 	SXIWRITE4(sc, 0, reg);
7130ea1c705Spatrick }
7140ea1c705Spatrick 
7150ea1c705Spatrick #define CCU_APB1_CLK_RAT_N(x)		(((x) >> 16) & 0x3)
7160ea1c705Spatrick #define CCU_APB1_CLK_RAT_M(x)		(((x) >> 0) & 0x1f)
7170ea1c705Spatrick #define CCU_APB1_CLK_SRC_SEL(x)		(((x) >> 24) & 0x3)
7180ea1c705Spatrick 
7190ea1c705Spatrick uint32_t
sxiccmu_apb1_get_frequency(void * cookie,uint32_t * cells)7200ea1c705Spatrick sxiccmu_apb1_get_frequency(void *cookie, uint32_t *cells)
7210ea1c705Spatrick {
7220ea1c705Spatrick 	struct sxiccmu_clock *sc = cookie;
7230ea1c705Spatrick 	uint32_t reg, m, n, freq;
7240ea1c705Spatrick 	int idx;
7250ea1c705Spatrick 
7260ea1c705Spatrick 	reg = SXIREAD4(sc, 0);
7270ea1c705Spatrick 	m = CCU_APB1_CLK_RAT_M(reg);
7280ea1c705Spatrick 	n = CCU_APB1_CLK_RAT_N(reg);
7290ea1c705Spatrick 	idx = CCU_APB1_CLK_SRC_SEL(reg);
7300ea1c705Spatrick 
7310ea1c705Spatrick 	freq = clock_get_frequency_idx(sc->sc_node, idx);
7320ea1c705Spatrick 	return freq / (1 << n) / (m + 1);
7330ea1c705Spatrick }
7340ea1c705Spatrick 
7355e83a44fSkettenis #define CCU_CPUS_CLK_SRC_SEL(x)		(((x) >> 16) & 0x3)
7365e83a44fSkettenis #define CCU_CPUS_POST_DIV(x)		(((x) >> 8) & 0x1f)
7375e83a44fSkettenis #define CCU_CPUS_CLK_RATIO(x)		(((x) >> 0) & 0x3)
7385e83a44fSkettenis 
7395e83a44fSkettenis uint32_t
sxiccmu_cpus_get_frequency(void * cookie,uint32_t * cells)7405e83a44fSkettenis sxiccmu_cpus_get_frequency(void *cookie, uint32_t *cells)
7415e83a44fSkettenis {
7425e83a44fSkettenis 	struct sxiccmu_clock *sc = cookie;
7435e83a44fSkettenis 	uint32_t reg, post_div, clk_ratio, freq;
7445e83a44fSkettenis 	int idx;
7455e83a44fSkettenis 
7465e83a44fSkettenis 	reg = SXIREAD4(sc, 0);
7475e83a44fSkettenis 	idx = CCU_CPUS_CLK_SRC_SEL(reg);
7485e83a44fSkettenis 	post_div = (idx == 2 ? CCU_CPUS_POST_DIV(reg): 0);
7495e83a44fSkettenis 	clk_ratio = CCU_CPUS_CLK_RATIO(reg);
7505e83a44fSkettenis 
7515e83a44fSkettenis 	freq = clock_get_frequency_idx(sc->sc_node, idx);
7525e83a44fSkettenis 	return freq / (clk_ratio + 1) / (post_div + 1);
7535e83a44fSkettenis }
7545e83a44fSkettenis 
7555e83a44fSkettenis #define CCU_APBS_CLK_RATIO(x)		(((x) >> 0) & 0x3)
7565e83a44fSkettenis 
7575e83a44fSkettenis uint32_t
sxiccmu_apbs_get_frequency(void * cookie,uint32_t * cells)7585e83a44fSkettenis sxiccmu_apbs_get_frequency(void *cookie, uint32_t *cells)
7595e83a44fSkettenis {
7605e83a44fSkettenis 	struct sxiccmu_clock *sc = cookie;
7615e83a44fSkettenis 	uint32_t reg, freq;
7625e83a44fSkettenis 
7635e83a44fSkettenis 	reg = SXIREAD4(sc, 0);
7645e83a44fSkettenis 	freq = clock_get_frequency(sc->sc_node, NULL);
7655e83a44fSkettenis 	return freq / (CCU_APBS_CLK_RATIO(reg) + 1);
7665e83a44fSkettenis }
7675e83a44fSkettenis 
7680ea1c705Spatrick #define	CCU_GMAC_CLK_PIT		(1 << 2)
7690ea1c705Spatrick #define	CCU_GMAC_CLK_TCS		(3 << 0)
7700ea1c705Spatrick #define	CCU_GMAC_CLK_TCS_MII		0
7710ea1c705Spatrick #define	CCU_GMAC_CLK_TCS_EXT_125	1
7720ea1c705Spatrick #define	CCU_GMAC_CLK_TCS_INT_RGMII	2
7730ea1c705Spatrick 
7740ea1c705Spatrick int
sxiccmu_gmac_set_frequency(void * cookie,uint32_t * cells,uint32_t freq)7750ea1c705Spatrick sxiccmu_gmac_set_frequency(void *cookie, uint32_t *cells, uint32_t freq)
7760ea1c705Spatrick {
7770ea1c705Spatrick 	struct sxiccmu_clock *sc = cookie;
7780ea1c705Spatrick 
7790ea1c705Spatrick 	switch (freq) {
7800ea1c705Spatrick 	case 25000000:		/* MMI, 25 MHz */
7810ea1c705Spatrick 		SXICMS4(sc, 0, CCU_GMAC_CLK_PIT|CCU_GMAC_CLK_TCS,
7820ea1c705Spatrick 		    CCU_GMAC_CLK_TCS_MII);
7830ea1c705Spatrick 		break;
7840ea1c705Spatrick 	case 125000000:		/* RGMII, 125 MHz */
7850ea1c705Spatrick 		SXICMS4(sc, 0, CCU_GMAC_CLK_PIT|CCU_GMAC_CLK_TCS,
7860ea1c705Spatrick 		    CCU_GMAC_CLK_PIT|CCU_GMAC_CLK_TCS_INT_RGMII);
7870ea1c705Spatrick 		break;
7880ea1c705Spatrick 	default:
7890ea1c705Spatrick 		return -1;
7900ea1c705Spatrick 	}
7910ea1c705Spatrick 
7920ea1c705Spatrick 	return 0;
7930ea1c705Spatrick }
7940ea1c705Spatrick 
7950ea1c705Spatrick #define CCU_SDx_SCLK_GATING		(1U << 31)
7960ea1c705Spatrick #define CCU_SDx_CLK_SRC_SEL_OSC24M	(0 << 24)
7970ea1c705Spatrick #define CCU_SDx_CLK_SRC_SEL_PLL6	(1 << 24)
7980ea1c705Spatrick #define CCU_SDx_CLK_SRC_SEL_PLL5	(2 << 24)
7990ea1c705Spatrick #define CCU_SDx_CLK_SRC_SEL_MASK	(3 << 24)
8000ea1c705Spatrick #define CCU_SDx_CLK_DIV_RATIO_N_MASK	(3 << 16)
8010ea1c705Spatrick #define CCU_SDx_CLK_DIV_RATIO_N_SHIFT	16
8020ea1c705Spatrick #define CCU_SDx_CLK_DIV_RATIO_M_MASK	(7 << 0)
8030ea1c705Spatrick #define CCU_SDx_CLK_DIV_RATIO_M_SHIFT	0
8040ea1c705Spatrick 
8050ea1c705Spatrick int
sxiccmu_mmc_do_set_frequency(struct sxiccmu_clock * sc,uint32_t freq,uint32_t parent_freq)8060ea1c705Spatrick sxiccmu_mmc_do_set_frequency(struct sxiccmu_clock *sc, uint32_t freq,
8070ea1c705Spatrick     uint32_t parent_freq)
8080ea1c705Spatrick {
8090ea1c705Spatrick 	uint32_t reg, m, n;
8100ea1c705Spatrick 	uint32_t clk_src;
8110ea1c705Spatrick 
8120ea1c705Spatrick 	switch (freq) {
8130ea1c705Spatrick 	case 400000:
8140ea1c705Spatrick 		n = 2, m = 15;
8150ea1c705Spatrick 		clk_src = CCU_SDx_CLK_SRC_SEL_OSC24M;
8160ea1c705Spatrick 		break;
8171ed198b7Skettenis 	case 20000000:
8180ea1c705Spatrick 	case 25000000:
8190ea1c705Spatrick 	case 26000000:
8200ea1c705Spatrick 	case 50000000:
8210ea1c705Spatrick 	case 52000000:
8220ea1c705Spatrick 		n = 0, m = 0;
8230ea1c705Spatrick 		clk_src = CCU_SDx_CLK_SRC_SEL_PLL6;
8240ea1c705Spatrick 		while ((parent_freq / (1 << n) / 16) > freq)
8250ea1c705Spatrick 			n++;
8260ea1c705Spatrick 		while ((parent_freq / (1 << n) / (m + 1)) > freq)
8270ea1c705Spatrick 			m++;
8280ea1c705Spatrick 		break;
8290ea1c705Spatrick 	default:
8300ea1c705Spatrick 		return -1;
8310ea1c705Spatrick 	}
8320ea1c705Spatrick 
8330ea1c705Spatrick 	reg = SXIREAD4(sc, 0);
8340ea1c705Spatrick 	reg &= ~CCU_SDx_CLK_SRC_SEL_MASK;
8350ea1c705Spatrick 	reg |= clk_src;
8360ea1c705Spatrick 	reg &= ~CCU_SDx_CLK_DIV_RATIO_N_MASK;
8370ea1c705Spatrick 	reg |= n << CCU_SDx_CLK_DIV_RATIO_N_SHIFT;
8380ea1c705Spatrick 	reg &= ~CCU_SDx_CLK_DIV_RATIO_M_MASK;
8390ea1c705Spatrick 	reg |= m << CCU_SDx_CLK_DIV_RATIO_M_SHIFT;
8400ea1c705Spatrick 	SXIWRITE4(sc, 0, reg);
8410ea1c705Spatrick 
8420ea1c705Spatrick 	return 0;
8430ea1c705Spatrick }
8440ea1c705Spatrick 
8450ea1c705Spatrick int
sxiccmu_mmc_set_frequency(void * cookie,uint32_t * cells,uint32_t freq)8460ea1c705Spatrick sxiccmu_mmc_set_frequency(void *cookie, uint32_t *cells, uint32_t freq)
8470ea1c705Spatrick {
8480ea1c705Spatrick 	struct sxiccmu_clock *sc = cookie;
8490ea1c705Spatrick 	uint32_t parent_freq;
8500ea1c705Spatrick 
8510ea1c705Spatrick 	if (cells[0] != 0)
8520ea1c705Spatrick 		return -1;
8530ea1c705Spatrick 
8540ea1c705Spatrick 	parent_freq = clock_get_frequency_idx(sc->sc_node, 1);
8550ea1c705Spatrick 	return sxiccmu_mmc_do_set_frequency(sc, freq, parent_freq);
8560ea1c705Spatrick }
8570ea1c705Spatrick 
8580ea1c705Spatrick void
sxiccmu_mmc_enable(void * cookie,uint32_t * cells,int on)8590ea1c705Spatrick sxiccmu_mmc_enable(void *cookie, uint32_t *cells, int on)
8600ea1c705Spatrick {
8610ea1c705Spatrick 	struct sxiccmu_clock *sc = cookie;
8620ea1c705Spatrick 
8630ea1c705Spatrick 	if (cells[0] != 0)
8640ea1c705Spatrick 		return;
8650ea1c705Spatrick 
8660ea1c705Spatrick 	if (on)
8670ea1c705Spatrick 		SXISET4(sc, 0, CCU_SDx_SCLK_GATING);
8680ea1c705Spatrick 	else
8690ea1c705Spatrick 		SXICLR4(sc, 0, CCU_SDx_SCLK_GATING);
8700ea1c705Spatrick }
8710ea1c705Spatrick 
8720ea1c705Spatrick void
sxiccmu_gate_enable(void * cookie,uint32_t * cells,int on)8730ea1c705Spatrick sxiccmu_gate_enable(void *cookie, uint32_t *cells, int on)
8740ea1c705Spatrick {
8750ea1c705Spatrick 	struct sxiccmu_clock *sc = cookie;
8760ea1c705Spatrick 	int reg = cells[0] / 32;
8770ea1c705Spatrick 	int bit = cells[0] % 32;
8780ea1c705Spatrick 
8790ea1c705Spatrick 	if (on) {
8800ea1c705Spatrick 		clock_enable(sc->sc_node, NULL);
8810ea1c705Spatrick 		SXISET4(sc, reg * 4, (1U << bit));
8820ea1c705Spatrick 	} else {
8830ea1c705Spatrick 		SXICLR4(sc, reg * 4, (1U << bit));
8840ea1c705Spatrick 		clock_disable(sc->sc_node, NULL);
8850ea1c705Spatrick 	}
8860ea1c705Spatrick }
8870ea1c705Spatrick 
8880ea1c705Spatrick void
sxiccmu_reset(void * cookie,uint32_t * cells,int assert)8890ea1c705Spatrick sxiccmu_reset(void *cookie, uint32_t *cells, int assert)
8900ea1c705Spatrick {
8910ea1c705Spatrick 	struct sxiccmu_clock *sc = cookie;
8920ea1c705Spatrick 	int reg = cells[0] / 32;
8930ea1c705Spatrick 	int bit = cells[0] % 32;
8940ea1c705Spatrick 
8950ea1c705Spatrick 	if (assert)
8960ea1c705Spatrick 		SXICLR4(sc, reg * 4, (1U << bit));
8970ea1c705Spatrick 	else
8980ea1c705Spatrick 		SXISET4(sc, reg * 4, (1U << bit));
8990ea1c705Spatrick }
9000ea1c705Spatrick 
9010ea1c705Spatrick /*
902b5fbf381Skettenis  * Newer device trees, such as those for the Allwinner H3/A64 have
903b5fbf381Skettenis  * most of the clock nodes replaced with a single clock control unit
904b5fbf381Skettenis  * node.
9050ea1c705Spatrick  */
9060ea1c705Spatrick 
9070ea1c705Spatrick uint32_t
sxiccmu_ccu_get_frequency(void * cookie,uint32_t * cells)9080ea1c705Spatrick sxiccmu_ccu_get_frequency(void *cookie, uint32_t *cells)
9090ea1c705Spatrick {
9100ea1c705Spatrick 	struct sxiccmu_softc *sc = cookie;
9110ea1c705Spatrick 	uint32_t idx = cells[0];
9120ea1c705Spatrick 	uint32_t parent;
9130ea1c705Spatrick 
9140ea1c705Spatrick 	if (idx < sc->sc_ngates && sc->sc_gates[idx].parent) {
9150ea1c705Spatrick 		parent = sc->sc_gates[idx].parent;
9160ea1c705Spatrick 		return sxiccmu_ccu_get_frequency(sc, &parent);
9170ea1c705Spatrick 	}
9180ea1c705Spatrick 
9190ea1c705Spatrick 	return sc->sc_get_frequency(sc, idx);
9200ea1c705Spatrick }
9210ea1c705Spatrick 
922199786d9Skettenis /* Allwinner A10/A10s/A13/A20 */
923d524c0faSkettenis #define A10_PLL1_CFG_REG		0x0000
924193b1cd6Skettenis #define A10_PLL1_OUT_EXT_DIVP_MASK	(0x3 << 16)
925193b1cd6Skettenis #define A10_PLL1_OUT_EXT_DIVP_SHIFT	16
926d524c0faSkettenis #define A10_PLL1_OUT_EXT_DIVP(x)	(((x) >> 16) & 0x3)
927d524c0faSkettenis #define A10_PLL1_FACTOR_N(x)		(((x) >> 8) & 0x1f)
928193b1cd6Skettenis #define A10_PLL1_FACTOR_N_MASK		(0x1f << 8)
929193b1cd6Skettenis #define A10_PLL1_FACTOR_N_SHIFT		8
930d524c0faSkettenis #define A10_PLL1_FACTOR_K(x)		(((x) >> 4) & 0x3)
931193b1cd6Skettenis #define A10_PLL1_FACTOR_K_MASK		(0x3 << 4)
932193b1cd6Skettenis #define A10_PLL1_FACTOR_K_SHIFT		4
933d524c0faSkettenis #define A10_PLL1_FACTOR_M(x)		(((x) >> 0) & 0x3)
934193b1cd6Skettenis #define A10_PLL1_FACTOR_M_MASK		(0x3 << 0)
935193b1cd6Skettenis #define A10_PLL1_FACTOR_M_SHIFT		0
936d524c0faSkettenis #define A10_CPU_AHB_APB0_CFG_REG	0x0054
937d524c0faSkettenis #define A10_CPU_CLK_SRC_SEL		(0x3 << 16)
938d524c0faSkettenis #define A10_CPU_CLK_SRC_SEL_LOSC	(0x0 << 16)
939d524c0faSkettenis #define A10_CPU_CLK_SRC_SEL_OSC24M	(0x1 << 16)
940d524c0faSkettenis #define A10_CPU_CLK_SRC_SEL_PLL1	(0x2 << 16)
941d524c0faSkettenis #define A10_CPU_CLK_SRC_SEL_200MHZ	(0x3 << 16)
942ea5e035fSkettenis #define A10_AHB_CLK_DIV_RATIO(x)	(((x) >> 8) & 0x3)
943ea5e035fSkettenis #define A10_AXI_CLK_DIV_RATIO(x)	(((x) >> 0) & 0x3)
944d524c0faSkettenis 
945d524c0faSkettenis uint32_t
sxiccmu_a10_get_frequency(struct sxiccmu_softc * sc,uint32_t idx)946d524c0faSkettenis sxiccmu_a10_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
947d524c0faSkettenis {
948d524c0faSkettenis 	uint32_t parent;
949ea5e035fSkettenis 	uint32_t reg, div;
950ea5e035fSkettenis 	uint32_t k, m, n, p;
951d524c0faSkettenis 
952d524c0faSkettenis 	switch (idx) {
953d524c0faSkettenis 	case A10_CLK_LOSC:
954d524c0faSkettenis 		return clock_get_frequency(sc->sc_node, "losc");
955d524c0faSkettenis 	case A10_CLK_HOSC:
956d524c0faSkettenis 		return clock_get_frequency(sc->sc_node, "hosc");
957d524c0faSkettenis 	case A10_CLK_PLL_CORE:
958d524c0faSkettenis 		reg = SXIREAD4(sc, A10_PLL1_CFG_REG);
959d524c0faSkettenis 		k = A10_PLL1_FACTOR_K(reg) + 1;
960d524c0faSkettenis 		m = A10_PLL1_FACTOR_M(reg) + 1;
961d524c0faSkettenis 		n = A10_PLL1_FACTOR_N(reg);
962d524c0faSkettenis 		p = 1 << A10_PLL1_OUT_EXT_DIVP(reg);
963d524c0faSkettenis 		return (24000000 * n * k) / (m * p);
964d524c0faSkettenis 	case A10_CLK_PLL_PERIPH_BASE:
965d524c0faSkettenis 		/* Not hardcoded, but recommended. */
966d524c0faSkettenis 		return 600000000;
967d524c0faSkettenis 	case A10_CLK_PLL_PERIPH:
968d524c0faSkettenis 		return sxiccmu_a10_get_frequency(sc, A10_CLK_PLL_PERIPH_BASE) * 2;
969d524c0faSkettenis 	case A10_CLK_CPU:
970d524c0faSkettenis 		reg = SXIREAD4(sc, A10_CPU_AHB_APB0_CFG_REG);
971d524c0faSkettenis 		switch (reg & A10_CPU_CLK_SRC_SEL) {
972d524c0faSkettenis 		case A10_CPU_CLK_SRC_SEL_LOSC:
973d524c0faSkettenis 			parent = A10_CLK_LOSC;
974d524c0faSkettenis 			break;
975d524c0faSkettenis 		case A10_CPU_CLK_SRC_SEL_OSC24M:
976d524c0faSkettenis 			parent = A10_CLK_HOSC;
977d524c0faSkettenis 			break;
978d524c0faSkettenis 		case A10_CPU_CLK_SRC_SEL_PLL1:
979d524c0faSkettenis 			parent = A10_CLK_PLL_CORE;
980d524c0faSkettenis 			break;
981d524c0faSkettenis 		case A10_CPU_CLK_SRC_SEL_200MHZ:
982d524c0faSkettenis 			return 200000000;
983d524c0faSkettenis 		}
984d524c0faSkettenis 		return sxiccmu_ccu_get_frequency(sc, &parent);
985ea5e035fSkettenis 	case A10_CLK_AXI:
986ea5e035fSkettenis 		reg = SXIREAD4(sc, A10_CPU_AHB_APB0_CFG_REG);
987ea5e035fSkettenis 		div = 1 << A10_AXI_CLK_DIV_RATIO(reg);
988ea5e035fSkettenis 		parent = A10_CLK_CPU;
989ea5e035fSkettenis 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
990ea5e035fSkettenis 	case A10_CLK_AHB:
991ea5e035fSkettenis 		reg = SXIREAD4(sc, A10_CPU_AHB_APB0_CFG_REG);
992ea5e035fSkettenis 		div = 1 << A10_AHB_CLK_DIV_RATIO(reg);
993ea5e035fSkettenis 		parent = A10_CLK_AXI;
994ea5e035fSkettenis 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
995d524c0faSkettenis 	case A10_CLK_APB1:
996d524c0faSkettenis 		/* XXX Controlled by a MUX. */
997d524c0faSkettenis 		return 24000000;
998d524c0faSkettenis 	}
999d524c0faSkettenis 
1000d524c0faSkettenis 	printf("%s: 0x%08x\n", __func__, idx);
1001d524c0faSkettenis 	return 0;
1002d524c0faSkettenis }
1003d524c0faSkettenis 
1004199786d9Skettenis uint32_t
sxiccmu_a10s_get_frequency(struct sxiccmu_softc * sc,uint32_t idx)1005199786d9Skettenis sxiccmu_a10s_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
1006199786d9Skettenis {
1007199786d9Skettenis 	uint32_t parent;
1008199786d9Skettenis 	uint32_t reg, div;
1009199786d9Skettenis 	uint32_t k, m, n, p;
1010199786d9Skettenis 
1011199786d9Skettenis 	switch (idx) {
1012199786d9Skettenis 	case A10S_CLK_LOSC:
1013199786d9Skettenis 		return clock_get_frequency(sc->sc_node, "losc");
1014199786d9Skettenis 	case A10S_CLK_HOSC:
1015199786d9Skettenis 		return clock_get_frequency(sc->sc_node, "hosc");
1016199786d9Skettenis 	case A10S_CLK_PLL_CORE:
1017199786d9Skettenis 		reg = SXIREAD4(sc, A10_PLL1_CFG_REG);
1018199786d9Skettenis 		k = A10_PLL1_FACTOR_K(reg) + 1;
1019199786d9Skettenis 		m = A10_PLL1_FACTOR_M(reg) + 1;
1020199786d9Skettenis 		n = A10_PLL1_FACTOR_N(reg);
1021199786d9Skettenis 		p = 1 << A10_PLL1_OUT_EXT_DIVP(reg);
1022199786d9Skettenis 		return (24000000 * n * k) / (m * p);
1023199786d9Skettenis 	case A10S_CLK_PLL_PERIPH:
1024199786d9Skettenis 		return 1200000000;
1025199786d9Skettenis 	case A10S_CLK_CPU:
1026199786d9Skettenis 		reg = SXIREAD4(sc, A10_CPU_AHB_APB0_CFG_REG);
1027199786d9Skettenis 		switch (reg & A10_CPU_CLK_SRC_SEL) {
1028199786d9Skettenis 		case A10_CPU_CLK_SRC_SEL_LOSC:
1029199786d9Skettenis 			parent = A10S_CLK_LOSC;
1030199786d9Skettenis 			break;
1031199786d9Skettenis 		case A10_CPU_CLK_SRC_SEL_OSC24M:
1032199786d9Skettenis 			parent = A10S_CLK_HOSC;
1033199786d9Skettenis 			break;
1034199786d9Skettenis 		case A10_CPU_CLK_SRC_SEL_PLL1:
1035199786d9Skettenis 			parent = A10S_CLK_PLL_CORE;
1036199786d9Skettenis 			break;
1037199786d9Skettenis 		case A10_CPU_CLK_SRC_SEL_200MHZ:
1038199786d9Skettenis 			return 200000000;
1039199786d9Skettenis 		}
1040199786d9Skettenis 		return sxiccmu_ccu_get_frequency(sc, &parent);
1041199786d9Skettenis 	case A10S_CLK_AXI:
1042199786d9Skettenis 		reg = SXIREAD4(sc, A10_CPU_AHB_APB0_CFG_REG);
1043199786d9Skettenis 		div = 1 << A10_AXI_CLK_DIV_RATIO(reg);
1044199786d9Skettenis 		parent = A10S_CLK_CPU;
1045199786d9Skettenis 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
1046199786d9Skettenis 	case A10S_CLK_AHB:
1047199786d9Skettenis 		reg = SXIREAD4(sc, A10_CPU_AHB_APB0_CFG_REG);
1048199786d9Skettenis 		div = 1 << A10_AHB_CLK_DIV_RATIO(reg);
1049199786d9Skettenis 		parent = A10S_CLK_AXI;
1050199786d9Skettenis 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
1051199786d9Skettenis 	case A10S_CLK_APB1:
1052199786d9Skettenis 		/* XXX Controlled by a MUX. */
1053199786d9Skettenis 		return 24000000;
1054199786d9Skettenis 	}
1055199786d9Skettenis 
1056199786d9Skettenis 	printf("%s: 0x%08x\n", __func__, idx);
1057199786d9Skettenis 	return 0;
1058199786d9Skettenis }
1059199786d9Skettenis 
106029e54e85Skettenis /* Allwinner A23/A64/H3/H5/R40 */
1061b5fbf381Skettenis #define CCU_AHB1_APB1_CFG_REG		0x0054
1062b5fbf381Skettenis #define CCU_AHB1_CLK_SRC_SEL		(3 << 12)
1063b5fbf381Skettenis #define CCU_AHB1_CLK_SRC_SEL_LOSC	(0 << 12)
1064b5fbf381Skettenis #define CCU_AHB1_CLK_SRC_SEL_OSC24M	(1 << 12)
1065b5fbf381Skettenis #define CCU_AHB1_CLK_SRC_SEL_AXI	(2 << 12)
1066b5fbf381Skettenis #define CCU_AHB1_CLK_SRC_SEL_PERIPH0	(3 << 12)
1067b5fbf381Skettenis #define CCU_AHB1_PRE_DIV(x)		((((x) >> 6) & 3) + 1)
1068b5fbf381Skettenis #define CCU_AHB1_CLK_DIV_RATIO(x)	(1 << (((x) >> 4) & 3))
1069b5fbf381Skettenis #define CCU_AHB2_CFG_REG		0x005c
1070b5fbf381Skettenis #define CCU_AHB2_CLK_CFG		(3 << 0)
1071b5fbf381Skettenis 
10720ea1c705Spatrick uint32_t
sxiccmu_a23_get_frequency(struct sxiccmu_softc * sc,uint32_t idx)1073f0a8b882Skevlo sxiccmu_a23_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
1074f0a8b882Skevlo {
1075f0a8b882Skevlo 	uint32_t parent;
1076f0a8b882Skevlo 	uint32_t reg, div;
1077f0a8b882Skevlo 
1078f0a8b882Skevlo 	switch (idx) {
1079f0a8b882Skevlo 	case A23_CLK_LOSC:
1080f0a8b882Skevlo 		return clock_get_frequency(sc->sc_node, "losc");
1081f0a8b882Skevlo 	case A23_CLK_HOSC:
1082f0a8b882Skevlo 		return clock_get_frequency(sc->sc_node, "hosc");
1083f0a8b882Skevlo 	case A23_CLK_PLL_PERIPH:
1084f0a8b882Skevlo 		/* Not hardcoded, but recommended. */
1085f0a8b882Skevlo 		return 600000000;
1086f0a8b882Skevlo 	case A23_CLK_APB2:
1087f0a8b882Skevlo 		/* XXX Controlled by a MUX. */
1088f0a8b882Skevlo 		return 24000000;
1089f0a8b882Skevlo 	case A23_CLK_AHB1:
1090f0a8b882Skevlo 		reg = SXIREAD4(sc, CCU_AHB1_APB1_CFG_REG);
1091f0a8b882Skevlo 		div = CCU_AHB1_CLK_DIV_RATIO(reg);
1092f0a8b882Skevlo 		switch (reg & CCU_AHB1_CLK_SRC_SEL) {
1093f0a8b882Skevlo 		case CCU_AHB1_CLK_SRC_SEL_LOSC:
1094f0a8b882Skevlo 			parent = A23_CLK_LOSC;
1095f0a8b882Skevlo 			break;
1096f0a8b882Skevlo 		case CCU_AHB1_CLK_SRC_SEL_OSC24M:
1097f0a8b882Skevlo 			parent = A23_CLK_HOSC;
1098f0a8b882Skevlo 			break;
1099f0a8b882Skevlo 		case CCU_AHB1_CLK_SRC_SEL_AXI:
1100f0a8b882Skevlo 			parent = A23_CLK_AXI;
1101f0a8b882Skevlo 			break;
1102f0a8b882Skevlo 		case CCU_AHB1_CLK_SRC_SEL_PERIPH0:
1103f0a8b882Skevlo 			parent = A23_CLK_PLL_PERIPH;
1104f0a8b882Skevlo 			div *= CCU_AHB1_PRE_DIV(reg);
1105f0a8b882Skevlo 			break;
1106f0a8b882Skevlo 		default:
1107f0a8b882Skevlo 			return 0;
1108f0a8b882Skevlo 		}
1109f0a8b882Skevlo 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
1110f0a8b882Skevlo 	}
1111f0a8b882Skevlo 
1112f0a8b882Skevlo 	printf("%s: 0x%08x\n", __func__, idx);
1113f0a8b882Skevlo 	return 0;
1114f0a8b882Skevlo }
1115f0a8b882Skevlo 
1116bced15f9Skettenis #define A64_PLL_CPUX_CTRL_REG		0x0000
1117bced15f9Skettenis #define A64_PLL_CPUX_LOCK		(1 << 28)
1118bced15f9Skettenis #define A64_PLL_CPUX_OUT_EXT_DIVP(x)	(((x) >> 16) & 0x3)
1119bced15f9Skettenis #define A64_PLL_CPUX_OUT_EXT_DIVP_MASK	(0x3 << 16)
1120bced15f9Skettenis #define A64_PLL_CPUX_FACTOR_N(x)	(((x) >> 8) & 0x1f)
1121bced15f9Skettenis #define A64_PLL_CPUX_FACTOR_N_MASK	(0x1f << 8)
1122bced15f9Skettenis #define A64_PLL_CPUX_FACTOR_N_SHIFT	8
1123bced15f9Skettenis #define A64_PLL_CPUX_FACTOR_K(x)	(((x) >> 4) & 0x3)
1124bced15f9Skettenis #define A64_PLL_CPUX_FACTOR_K_MASK	(0x3 << 4)
1125bced15f9Skettenis #define A64_PLL_CPUX_FACTOR_K_SHIFT	4
1126bced15f9Skettenis #define A64_PLL_CPUX_FACTOR_M(x)	(((x) >> 0) & 0x3)
1127bced15f9Skettenis #define A64_PLL_CPUX_FACTOR_M_MASK	(0x3 << 0)
1128bced15f9Skettenis #define A64_CPUX_AXI_CFG_REG		0x0050
1129bced15f9Skettenis #define A64_CPUX_CLK_SRC_SEL		(0x3 << 16)
1130bced15f9Skettenis #define A64_CPUX_CLK_SRC_SEL_LOSC	(0x0 << 16)
1131bced15f9Skettenis #define A64_CPUX_CLK_SRC_SEL_OSC24M	(0x1 << 16)
1132bced15f9Skettenis #define A64_CPUX_CLK_SRC_SEL_PLL_CPUX	(0x2 << 16)
1133bced15f9Skettenis 
1134f0a8b882Skevlo uint32_t
sxiccmu_a64_get_frequency(struct sxiccmu_softc * sc,uint32_t idx)11350ea1c705Spatrick sxiccmu_a64_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
11360ea1c705Spatrick {
1137fcb049cbSpatrick 	uint32_t parent;
1138fcb049cbSpatrick 	uint32_t reg, div;
1139bced15f9Skettenis 	uint32_t k, m, n, p;
1140fcb049cbSpatrick 
11410ea1c705Spatrick 	switch (idx) {
1142bced15f9Skettenis 	case A64_CLK_PLL_CPUX:
1143bced15f9Skettenis 		reg = SXIREAD4(sc, A64_PLL_CPUX_CTRL_REG);
1144bced15f9Skettenis 		k = A64_PLL_CPUX_FACTOR_K(reg) + 1;
1145bced15f9Skettenis 		m = A64_PLL_CPUX_FACTOR_M(reg) + 1;
1146bced15f9Skettenis 		n = A64_PLL_CPUX_FACTOR_N(reg) + 1;
1147bced15f9Skettenis 		p = 1 << A64_PLL_CPUX_OUT_EXT_DIVP(reg);
1148bced15f9Skettenis 		return (24000000 * n * k) / (m * p);
1149bced15f9Skettenis 	case A64_CLK_CPUX:
1150bced15f9Skettenis 		reg = SXIREAD4(sc, A64_CPUX_AXI_CFG_REG);
1151bced15f9Skettenis 		switch (reg & A64_CPUX_CLK_SRC_SEL) {
1152bced15f9Skettenis 		case A64_CPUX_CLK_SRC_SEL_LOSC:
1153bced15f9Skettenis 			parent = A64_CLK_LOSC;
1154bced15f9Skettenis 			break;
1155bced15f9Skettenis 		case A64_CPUX_CLK_SRC_SEL_OSC24M:
1156bced15f9Skettenis 			parent = A64_CLK_HOSC;
1157bced15f9Skettenis 			break;
1158bced15f9Skettenis 		case A64_CPUX_CLK_SRC_SEL_PLL_CPUX:
1159bced15f9Skettenis 			parent = A64_CLK_PLL_CPUX;
1160bced15f9Skettenis 			break;
1161bced15f9Skettenis 		default:
1162bced15f9Skettenis 			return 0;
1163bced15f9Skettenis 		}
1164bced15f9Skettenis 		return sxiccmu_ccu_get_frequency(sc, &parent);
1165fcb049cbSpatrick 	case A64_CLK_LOSC:
1166fcb049cbSpatrick 		return clock_get_frequency(sc->sc_node, "losc");
1167fcb049cbSpatrick 	case A64_CLK_HOSC:
1168fcb049cbSpatrick 		return clock_get_frequency(sc->sc_node, "hosc");
11690ea1c705Spatrick 	case A64_CLK_PLL_PERIPH0:
1170b5fbf381Skettenis 		/* Not hardcoded, but recommended. */
11710ea1c705Spatrick 		return 600000000;
11720ea1c705Spatrick 	case A64_CLK_PLL_PERIPH0_2X:
11730ea1c705Spatrick 		return sxiccmu_a64_get_frequency(sc, A64_CLK_PLL_PERIPH0) * 2;
11740ea1c705Spatrick 	case A64_CLK_APB2:
11750ea1c705Spatrick 		/* XXX Controlled by a MUX. */
11760ea1c705Spatrick 		return 24000000;
1177fcb049cbSpatrick 	case A64_CLK_AHB1:
1178fcb049cbSpatrick 		reg = SXIREAD4(sc, CCU_AHB1_APB1_CFG_REG);
1179fcb049cbSpatrick 		div = CCU_AHB1_CLK_DIV_RATIO(reg);
1180fcb049cbSpatrick 		switch (reg & CCU_AHB1_CLK_SRC_SEL) {
1181fcb049cbSpatrick 		case CCU_AHB1_CLK_SRC_SEL_LOSC:
1182fcb049cbSpatrick 			parent = A64_CLK_LOSC;
1183fcb049cbSpatrick 			break;
1184fcb049cbSpatrick 		case CCU_AHB1_CLK_SRC_SEL_OSC24M:
1185fcb049cbSpatrick 			parent = A64_CLK_HOSC;
1186fcb049cbSpatrick 			break;
1187fcb049cbSpatrick 		case CCU_AHB1_CLK_SRC_SEL_AXI:
1188fcb049cbSpatrick 			parent = A64_CLK_AXI;
1189fcb049cbSpatrick 			break;
1190fcb049cbSpatrick 		case CCU_AHB1_CLK_SRC_SEL_PERIPH0:
1191fcb049cbSpatrick 			parent = A64_CLK_PLL_PERIPH0;
1192fcb049cbSpatrick 			div *= CCU_AHB1_PRE_DIV(reg);
1193fcb049cbSpatrick 			break;
1194fcb049cbSpatrick 		default:
1195fcb049cbSpatrick 			return 0;
1196fcb049cbSpatrick 		}
1197fcb049cbSpatrick 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
1198fcb049cbSpatrick 	case A64_CLK_AHB2:
1199fcb049cbSpatrick 		reg = SXIREAD4(sc, CCU_AHB2_CFG_REG);
1200fcb049cbSpatrick 		switch (reg & CCU_AHB2_CLK_CFG) {
1201fcb049cbSpatrick 		case 0:
1202fcb049cbSpatrick 			parent = A64_CLK_AHB1;
1203fcb049cbSpatrick 			div = 1;
1204fcb049cbSpatrick 			break;
1205fcb049cbSpatrick 		case 1:
1206fcb049cbSpatrick 			parent = A64_CLK_PLL_PERIPH0;
1207fcb049cbSpatrick 			div = 2;
1208fcb049cbSpatrick 			break;
1209fcb049cbSpatrick 		default:
1210fcb049cbSpatrick 			return 0;
1211fcb049cbSpatrick 		}
1212fcb049cbSpatrick 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
12130ea1c705Spatrick 	}
12140ea1c705Spatrick 
12150ea1c705Spatrick 	printf("%s: 0x%08x\n", __func__, idx);
12160ea1c705Spatrick 	return 0;
12170ea1c705Spatrick }
12180ea1c705Spatrick 
1219cf192b2fSkettenis #define A80_AHB1_CLK_CFG_REG		0x0064
1220cf192b2fSkettenis #define A80_AHB1_SRC_CLK_SELECT		(3 << 24)
1221cf192b2fSkettenis #define A80_AHB1_SRC_CLK_SELECT_GTBUS	(0 << 24)
1222cf192b2fSkettenis #define A80_AHB1_SRC_CLK_SELECT_PERIPH0	(1 << 24)
1223cf192b2fSkettenis #define A80_AHB1_CLK_DIV_RATIO(x)	(1 << ((x) & 0x3))
1224cf192b2fSkettenis 
12250ea1c705Spatrick uint32_t
sxiccmu_a80_get_frequency(struct sxiccmu_softc * sc,uint32_t idx)1226d526c0edSkettenis sxiccmu_a80_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
1227d526c0edSkettenis {
1228cf192b2fSkettenis 	uint32_t parent;
1229cf192b2fSkettenis 	uint32_t reg, div;
1230cf192b2fSkettenis 
1231d526c0edSkettenis 	switch (idx) {
1232d526c0edSkettenis 	case A80_CLK_PLL_PERIPH0:
1233d526c0edSkettenis 		/* Not hardcoded, but recommended. */
1234d526c0edSkettenis 		return 960000000;
1235cf192b2fSkettenis 	case A80_CLK_AHB1:
1236cf192b2fSkettenis 		reg = SXIREAD4(sc, A80_AHB1_CLK_CFG_REG);
1237cf192b2fSkettenis 		div = A80_AHB1_CLK_DIV_RATIO(reg);
1238cf192b2fSkettenis 		switch (reg & A80_AHB1_SRC_CLK_SELECT) {
1239cf192b2fSkettenis 		case A80_AHB1_SRC_CLK_SELECT_GTBUS:
1240cf192b2fSkettenis 			parent = A80_CLK_GTBUS;
1241cf192b2fSkettenis 			break;
1242cf192b2fSkettenis 		case A80_AHB1_SRC_CLK_SELECT_PERIPH0:
1243cf192b2fSkettenis 			parent = A80_CLK_PLL_PERIPH0;
1244cf192b2fSkettenis 			break;
1245cf192b2fSkettenis 		default:
1246cf192b2fSkettenis 			parent = A80_CLK_PLL_PERIPH1;
1247cf192b2fSkettenis 			break;
1248cf192b2fSkettenis 		}
1249cf192b2fSkettenis 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
1250d526c0edSkettenis 	case A80_CLK_APB1:
1251d526c0edSkettenis 		/* XXX Controlled by a MUX. */
1252d526c0edSkettenis 		return 24000000;
1253d526c0edSkettenis 	}
1254d526c0edSkettenis 
1255d526c0edSkettenis 	printf("%s: 0x%08x\n", __func__, idx);
1256d526c0edSkettenis 	return 0;
1257d526c0edSkettenis }
1258d526c0edSkettenis 
12594e48f70dSkettenis /* Allwinner D1 */
12604718ccb1Skettenis #define D1_PLL_CPU_CTRL_REG		0x0000
12614718ccb1Skettenis #define D1_PLL_CPU_FACTOR_M(x)		(((x) >> 0) & 0x3)
12624718ccb1Skettenis #define D1_PLL_CPU_FACTOR_N(x)		(((x) >> 8) & 0xff)
12634718ccb1Skettenis #define D1_RISCV_CLK_REG		0x0d00
12644718ccb1Skettenis #define D1_RISCV_CLK_SEL		(7 << 24)
12654718ccb1Skettenis #define D1_RISCV_CLK_SEL_HOSC		(0 << 24)
12664718ccb1Skettenis #define D1_RISCV_CLK_SEL_PLL_CPU	(5 << 24)
12674718ccb1Skettenis #define D1_RISCV_DIV_CFG_FACTOR_M(x)	(((x) >> 0) & 0x1f)
1268*95c4b0b5Skevlo #define D1_PSI_CLK_REG			0x0510
1269*95c4b0b5Skevlo #define D1_PSI_CLK_FACTOR_N(x)		(((x) >> 8) & 0x3)
1270*95c4b0b5Skevlo #define D1_PSI_CLK_FACTOR_M(x)		(((x) >> 0) & 0x3)
12714e48f70dSkettenis 
12724e48f70dSkettenis uint32_t
sxiccmu_d1_get_frequency(struct sxiccmu_softc * sc,uint32_t idx)12734e48f70dSkettenis sxiccmu_d1_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
12744e48f70dSkettenis {
12754718ccb1Skettenis 	uint32_t parent;
1276*95c4b0b5Skevlo 	uint32_t reg, freq;
12774718ccb1Skettenis 	uint32_t m, n;
12784718ccb1Skettenis 
12794e48f70dSkettenis 	switch (idx) {
12804718ccb1Skettenis 	case D1_CLK_HOSC:
12814718ccb1Skettenis 		return clock_get_frequency(sc->sc_node, "hosc");
12824718ccb1Skettenis 	case D1_CLK_PLL_CPU:
12834718ccb1Skettenis 		reg = SXIREAD4(sc, D1_PLL_CPU_CTRL_REG);
12844718ccb1Skettenis 		m = D1_PLL_CPU_FACTOR_M(reg) + 1;
12854718ccb1Skettenis 		n = D1_PLL_CPU_FACTOR_N(reg) + 1;
12864718ccb1Skettenis 		return (24000000 * n) / m;
12874718ccb1Skettenis 	case D1_CLK_PLL_PERIPH0:
12884718ccb1Skettenis 		/* Not hardcoded, but recommended. */
12894718ccb1Skettenis 		return 600000000;
12904e48f70dSkettenis 	case D1_CLK_APB1:
12914e48f70dSkettenis 		/* XXX Controlled by a MUX. */
12924e48f70dSkettenis 		return 24000000;
12934718ccb1Skettenis 	case D1_CLK_RISCV:
12944718ccb1Skettenis 		reg = SXIREAD4(sc, D1_RISCV_CLK_REG);
12954718ccb1Skettenis 		switch (reg & D1_RISCV_CLK_SEL) {
12964718ccb1Skettenis 		case D1_RISCV_CLK_SEL_HOSC:
12974718ccb1Skettenis 			parent = D1_CLK_HOSC;
12984718ccb1Skettenis 			break;
12994718ccb1Skettenis 		case D1_RISCV_CLK_SEL_PLL_CPU:
13004718ccb1Skettenis 			parent = D1_CLK_PLL_CPU;
13014718ccb1Skettenis 			break;
13024718ccb1Skettenis 		default:
13034718ccb1Skettenis 			return 0;
13044718ccb1Skettenis 		}
13054718ccb1Skettenis 		m = D1_RISCV_DIV_CFG_FACTOR_M(reg) + 1;
13064718ccb1Skettenis 		return sxiccmu_ccu_get_frequency(sc, &parent) / m;
1307*95c4b0b5Skevlo 	case D1_CLK_PSI_AHB:
1308*95c4b0b5Skevlo 		reg = SXIREAD4(sc, D1_PSI_CLK_REG);
1309*95c4b0b5Skevlo 		/* assume PLL_PERIPH0 source */
1310*95c4b0b5Skevlo 		freq = sxiccmu_d1_get_frequency(sc, D1_CLK_PLL_PERIPH0);
1311*95c4b0b5Skevlo 		m = D1_PSI_CLK_FACTOR_M(reg) + 1;
1312*95c4b0b5Skevlo 		n = 1 << D1_PSI_CLK_FACTOR_N(reg);
1313*95c4b0b5Skevlo 		return freq / (m * n);
13144e48f70dSkettenis 	}
13154e48f70dSkettenis 
13164e48f70dSkettenis 	printf("%s: 0x%08x\n", __func__, idx);
13174e48f70dSkettenis 	return 0;
13184e48f70dSkettenis }
13194e48f70dSkettenis 
13203c38ffe8Skettenis /* Allwinner H3/H5 */
13213c38ffe8Skettenis #define H3_PLL_CPUX_CTRL_REG		0x0000
1322dcec61dcSmiod #define H3_PLL_CPUX_ENABLE		(1U << 31)
1323f1089a02Skettenis #define H3_PLL_CPUX_LOCK		(1 << 28)
13243c38ffe8Skettenis #define H3_PLL_CPUX_OUT_EXT_DIVP(x)	(((x) >> 16) & 0x3)
1325f1089a02Skettenis #define H3_PLL_CPUX_OUT_EXT_DIVP_MASK	(0x3 << 16)
1326f1089a02Skettenis #define H3_PLL_CPUX_OUT_EXT_DIVP_SHIFT	16
13273c38ffe8Skettenis #define H3_PLL_CPUX_FACTOR_N(x)		(((x) >> 8) & 0x1f)
1328f1089a02Skettenis #define H3_PLL_CPUX_FACTOR_N_MASK	(0x1f << 8)
1329f1089a02Skettenis #define H3_PLL_CPUX_FACTOR_N_SHIFT	8
13303c38ffe8Skettenis #define H3_PLL_CPUX_FACTOR_K(x)		(((x) >> 4) & 0x3)
1331f1089a02Skettenis #define H3_PLL_CPUX_FACTOR_K_MASK	(0x3 << 4)
1332f1089a02Skettenis #define H3_PLL_CPUX_FACTOR_K_SHIFT	4
13333c38ffe8Skettenis #define H3_PLL_CPUX_FACTOR_M(x)		(((x) >> 0) & 0x3)
1334f1089a02Skettenis #define H3_PLL_CPUX_FACTOR_M_MASK	(0x3 << 0)
1335f1089a02Skettenis #define H3_PLL_CPUX_FACTOR_M_SHIFT	0
13363c38ffe8Skettenis #define H3_CPUX_AXI_CFG_REG		0x0050
13373c38ffe8Skettenis #define H3_CPUX_CLK_SRC_SEL		(0x3 << 16)
13383c38ffe8Skettenis #define H3_CPUX_CLK_SRC_SEL_LOSC	(0x0 << 16)
13393c38ffe8Skettenis #define H3_CPUX_CLK_SRC_SEL_OSC24M	(0x1 << 16)
13403c38ffe8Skettenis #define H3_CPUX_CLK_SRC_SEL_PLL_CPUX	(0x2 << 16)
13419424095dSuaa #define H3_PLL_STABLE_TIME_REG1		0x0204
13429424095dSuaa #define H3_PLL_STABLE_TIME_REG1_TIME(x)	(((x) >> 0) & 0xffff)
13433c38ffe8Skettenis 
1344d526c0edSkettenis uint32_t
sxiccmu_h3_get_frequency(struct sxiccmu_softc * sc,uint32_t idx)13450ea1c705Spatrick sxiccmu_h3_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
13460ea1c705Spatrick {
1347b5fbf381Skettenis 	uint32_t parent;
1348b5fbf381Skettenis 	uint32_t reg, div;
13493c38ffe8Skettenis 	uint32_t k, m, n, p;
1350b5fbf381Skettenis 
13510ea1c705Spatrick 	switch (idx) {
1352b5fbf381Skettenis 	case H3_CLK_LOSC:
1353b5fbf381Skettenis 		return clock_get_frequency(sc->sc_node, "losc");
1354b5fbf381Skettenis 	case H3_CLK_HOSC:
1355b5fbf381Skettenis 		return clock_get_frequency(sc->sc_node, "hosc");
13563c38ffe8Skettenis 	case H3_CLK_PLL_CPUX:
13573c38ffe8Skettenis 		reg = SXIREAD4(sc, H3_PLL_CPUX_CTRL_REG);
13583c38ffe8Skettenis 		k = H3_PLL_CPUX_FACTOR_K(reg) + 1;
13593c38ffe8Skettenis 		m = H3_PLL_CPUX_FACTOR_M(reg) + 1;
13603c38ffe8Skettenis 		n = H3_PLL_CPUX_FACTOR_N(reg) + 1;
13613c38ffe8Skettenis 		p = 1 << H3_PLL_CPUX_OUT_EXT_DIVP(reg);
13623c38ffe8Skettenis 		return (24000000 * n * k) / (m * p);
13630ea1c705Spatrick 	case H3_CLK_PLL_PERIPH0:
1364b5fbf381Skettenis 		/* Not hardcoded, but recommended. */
13650ea1c705Spatrick 		return 600000000;
13663c38ffe8Skettenis 	case H3_CLK_CPUX:
13673c38ffe8Skettenis 		reg = SXIREAD4(sc, H3_CPUX_AXI_CFG_REG);
13683c38ffe8Skettenis 		switch (reg & H3_CPUX_CLK_SRC_SEL) {
13693c38ffe8Skettenis 		case H3_CPUX_CLK_SRC_SEL_LOSC:
13703c38ffe8Skettenis 			parent = H3_CLK_LOSC;
13713c38ffe8Skettenis 			break;
13723c38ffe8Skettenis 		case H3_CPUX_CLK_SRC_SEL_OSC24M:
13733c38ffe8Skettenis 			parent = H3_CLK_HOSC;
13743c38ffe8Skettenis 			break;
13753c38ffe8Skettenis 		case H3_CPUX_CLK_SRC_SEL_PLL_CPUX:
13763c38ffe8Skettenis 			parent = H3_CLK_PLL_CPUX;
13773c38ffe8Skettenis 			break;
13783c38ffe8Skettenis 		default:
13793c38ffe8Skettenis 			return 0;
13803c38ffe8Skettenis 		}
13813c38ffe8Skettenis 		return sxiccmu_ccu_get_frequency(sc, &parent);
13820ea1c705Spatrick 	case H3_CLK_APB2:
13830ea1c705Spatrick 		/* XXX Controlled by a MUX. */
13840ea1c705Spatrick 		return 24000000;
1385b5fbf381Skettenis 	case H3_CLK_AHB1:
1386b5fbf381Skettenis 		reg = SXIREAD4(sc, CCU_AHB1_APB1_CFG_REG);
1387b5fbf381Skettenis 		div = CCU_AHB1_CLK_DIV_RATIO(reg);
1388b5fbf381Skettenis 		switch (reg & CCU_AHB1_CLK_SRC_SEL) {
1389b5fbf381Skettenis 		case CCU_AHB1_CLK_SRC_SEL_LOSC:
1390b5fbf381Skettenis 			parent = H3_CLK_LOSC;
1391b5fbf381Skettenis 			break;
1392b5fbf381Skettenis 		case CCU_AHB1_CLK_SRC_SEL_OSC24M:
1393b5fbf381Skettenis 			parent = H3_CLK_HOSC;
1394b5fbf381Skettenis 			break;
1395b5fbf381Skettenis 		case CCU_AHB1_CLK_SRC_SEL_AXI:
1396b5fbf381Skettenis 			parent = H3_CLK_AXI;
1397b5fbf381Skettenis 			break;
1398b5fbf381Skettenis 		case CCU_AHB1_CLK_SRC_SEL_PERIPH0:
1399b5fbf381Skettenis 			parent = H3_CLK_PLL_PERIPH0;
1400b5fbf381Skettenis 			div *= CCU_AHB1_PRE_DIV(reg);
1401b5fbf381Skettenis 			break;
1402b5fbf381Skettenis 		default:
1403b5fbf381Skettenis 			return 0;
1404b5fbf381Skettenis 		}
1405b5fbf381Skettenis 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
1406b5fbf381Skettenis 	case H3_CLK_AHB2:
1407b5fbf381Skettenis 		reg = SXIREAD4(sc, CCU_AHB2_CFG_REG);
1408b5fbf381Skettenis 		switch (reg & CCU_AHB2_CLK_CFG) {
1409b5fbf381Skettenis 		case 0:
1410b5fbf381Skettenis 			parent = H3_CLK_AHB1;
1411b5fbf381Skettenis 			div = 1;
1412b5fbf381Skettenis 			break;
1413b5fbf381Skettenis 		case 1:
1414b5fbf381Skettenis 			parent = H3_CLK_PLL_PERIPH0;
1415b5fbf381Skettenis 			div = 2;
1416b5fbf381Skettenis 			break;
1417b5fbf381Skettenis 		default:
1418b5fbf381Skettenis 			return 0;
1419b5fbf381Skettenis 		}
1420b5fbf381Skettenis 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
14210ea1c705Spatrick 	}
14220ea1c705Spatrick 
14230ea1c705Spatrick 	printf("%s: 0x%08x\n", __func__, idx);
14240ea1c705Spatrick 	return 0;
14250ea1c705Spatrick }
14260ea1c705Spatrick 
1427322e71d8Skettenis #define H3_AHB0_CLK_REG			0x0000
1428322e71d8Skettenis #define H3_AHB0_CLK_SRC_SEL		(0x3 << 16)
1429322e71d8Skettenis #define H3_AHB0_CLK_SRC_SEL_OSC32K	(0x0 << 16)
1430322e71d8Skettenis #define H3_AHB0_CLK_SRC_SEL_OSC24M	(0x1 << 16)
1431322e71d8Skettenis #define H3_AHB0_CLK_SRC_SEL_PLL_PERIPH0	(0x2 << 16)
1432322e71d8Skettenis #define H3_AHB0_CLK_SRC_SEL_IOSC	(0x3 << 16)
1433322e71d8Skettenis #define H3_AHB0_CLK_PRE_DIV(x)		((((x) >> 8) & 0x1f) + 1)
1434322e71d8Skettenis #define H3_AHB0_CLK_RATIO(x)		(1 << (((x) >> 4) & 3))
1435322e71d8Skettenis #define H3_APB0_CFG_REG			0x000c
1436322e71d8Skettenis #define H3_APB0_CLK_RATIO(x)		(1 << ((x) & 1))
1437322e71d8Skettenis 
1438322e71d8Skettenis uint32_t
sxiccmu_h3_r_get_frequency(struct sxiccmu_softc * sc,uint32_t idx)1439322e71d8Skettenis sxiccmu_h3_r_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
1440322e71d8Skettenis {
1441322e71d8Skettenis 	uint32_t parent;
1442322e71d8Skettenis 	uint32_t reg, div;
1443322e71d8Skettenis 	uint32_t freq;
1444322e71d8Skettenis 
1445322e71d8Skettenis 	switch (idx) {
1446322e71d8Skettenis 	case H3_R_CLK_AHB0:
1447322e71d8Skettenis 		reg = SXIREAD4(sc, H3_AHB0_CLK_REG);
1448322e71d8Skettenis 		switch (reg & H3_AHB0_CLK_SRC_SEL) {
1449322e71d8Skettenis 		case H3_AHB0_CLK_SRC_SEL_OSC32K:
1450322e71d8Skettenis 			freq = clock_get_frequency(sc->sc_node, "losc");
1451322e71d8Skettenis 			break;
1452322e71d8Skettenis 		case H3_AHB0_CLK_SRC_SEL_OSC24M:
1453322e71d8Skettenis 			freq = clock_get_frequency(sc->sc_node, "hosc");
1454322e71d8Skettenis 			break;
1455322e71d8Skettenis 		case H3_AHB0_CLK_SRC_SEL_PLL_PERIPH0:
1456322e71d8Skettenis 			freq = clock_get_frequency(sc->sc_node, "pll-periph");
1457322e71d8Skettenis 			break;
1458322e71d8Skettenis 		case H3_AHB0_CLK_SRC_SEL_IOSC:
1459322e71d8Skettenis 			freq = clock_get_frequency(sc->sc_node, "iosc");
1460322e71d8Skettenis 			break;
1461322e71d8Skettenis 		}
1462322e71d8Skettenis 		div = H3_AHB0_CLK_PRE_DIV(reg) * H3_AHB0_CLK_RATIO(reg);
1463322e71d8Skettenis 		return freq / div;
1464322e71d8Skettenis 	case H3_R_CLK_APB0:
1465322e71d8Skettenis 		reg = SXIREAD4(sc, H3_APB0_CFG_REG);
1466322e71d8Skettenis 		div = H3_APB0_CLK_RATIO(reg);
1467322e71d8Skettenis 		parent = H3_R_CLK_AHB0;
1468322e71d8Skettenis 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
1469322e71d8Skettenis 	}
1470322e71d8Skettenis 
1471322e71d8Skettenis 	printf("%s: 0x%08x\n", __func__, idx);
1472322e71d8Skettenis 	return 0;
1473322e71d8Skettenis }
1474322e71d8Skettenis 
1475e67d8589Suaa /* Allwinner H6 */
1476e67d8589Suaa #define H6_AHB3_CFG_REG		0x051c
1477e67d8589Suaa #define H6_AHB3_CLK_FACTOR_N(x)	(((x) >> 8) & 0x3)
1478e67d8589Suaa #define H6_AHB3_CLK_FACTOR_M(x)	(((x) >> 0) & 0x3)
1479e67d8589Suaa 
14802c064ff8Skettenis uint32_t
sxiccmu_h6_get_frequency(struct sxiccmu_softc * sc,uint32_t idx)14818b22851bSkettenis sxiccmu_h6_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
14828b22851bSkettenis {
1483e67d8589Suaa 	uint32_t reg, m, n;
1484e67d8589Suaa 	uint32_t freq;
1485e67d8589Suaa 
14868b22851bSkettenis 	switch (idx) {
14878b22851bSkettenis 	case H6_CLK_PLL_PERIPH0:
14888b22851bSkettenis 		/* Not hardcoded, but recommended. */
14898b22851bSkettenis 		return 600000000;
14908b22851bSkettenis 	case H6_CLK_PLL_PERIPH0_2X:
14918b22851bSkettenis 		return sxiccmu_h6_get_frequency(sc, H6_CLK_PLL_PERIPH0) * 2;
1492e67d8589Suaa 	case H6_CLK_AHB3:
1493e67d8589Suaa 		reg = SXIREAD4(sc, H6_AHB3_CFG_REG);
1494e67d8589Suaa 		/* assume PLL_PERIPH0 source */
1495e67d8589Suaa 		freq = sxiccmu_h6_get_frequency(sc, H6_CLK_PLL_PERIPH0);
1496e67d8589Suaa 		m = H6_AHB3_CLK_FACTOR_M(reg) + 1;
1497e67d8589Suaa 		n = 1 << H6_AHB3_CLK_FACTOR_N(reg);
1498e67d8589Suaa 		return freq / (m * n);
14998b22851bSkettenis 	case H6_CLK_APB2:
15008b22851bSkettenis 		/* XXX Controlled by a MUX. */
15018b22851bSkettenis 		return 24000000;
15028b22851bSkettenis 	}
15038b22851bSkettenis 
15048b22851bSkettenis 	printf("%s: 0x%08x\n", __func__, idx);
15058b22851bSkettenis 	return 0;
15068b22851bSkettenis }
15078b22851bSkettenis 
15088b22851bSkettenis uint32_t
sxiccmu_h6_r_get_frequency(struct sxiccmu_softc * sc,uint32_t idx)15098b22851bSkettenis sxiccmu_h6_r_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
15108b22851bSkettenis {
15118b22851bSkettenis 	switch (idx) {
15128b22851bSkettenis 	case H6_R_CLK_APB2:
15138b22851bSkettenis 		/* XXX Controlled by a MUX. */
15148b22851bSkettenis 		return 24000000;
151522652d99Suaa 	}
151622652d99Suaa 
151722652d99Suaa 	printf("%s: 0x%08x\n", __func__, idx);
151822652d99Suaa 	return 0;
151922652d99Suaa }
152022652d99Suaa 
152122652d99Suaa /* Allwinner H616 */
152222652d99Suaa #define H616_AHB3_CFG_REG		0x051c
152322652d99Suaa #define H616_AHB3_CLK_FACTOR_N(x)	(((x) >> 8) & 0x3)
152422652d99Suaa #define H616_AHB3_CLK_FACTOR_M(x)	(((x) >> 0) & 0x3)
152522652d99Suaa 
152622652d99Suaa uint32_t
sxiccmu_h616_get_frequency(struct sxiccmu_softc * sc,uint32_t idx)152722652d99Suaa sxiccmu_h616_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
152822652d99Suaa {
152922652d99Suaa 	uint32_t reg, m, n;
153022652d99Suaa 	uint32_t freq;
153122652d99Suaa 
153222652d99Suaa 	switch (idx) {
153322652d99Suaa 	case H616_CLK_PLL_PERIPH0:
153422652d99Suaa 		/* Not hardcoded, but recommended. */
153522652d99Suaa 		return 600000000;
153622652d99Suaa 	case H616_CLK_PLL_PERIPH0_2X:
153722652d99Suaa 		return sxiccmu_h616_get_frequency(sc, H616_CLK_PLL_PERIPH0) * 2;
153822652d99Suaa 	case H616_CLK_AHB3:
153922652d99Suaa 		reg = SXIREAD4(sc, H616_AHB3_CFG_REG);
154022652d99Suaa 		/* assume PLL_PERIPH0 source */
154122652d99Suaa 		freq = sxiccmu_h616_get_frequency(sc, H616_CLK_PLL_PERIPH0);
154222652d99Suaa 		m = H616_AHB3_CLK_FACTOR_M(reg) + 1;
154322652d99Suaa 		n = 1 << H616_AHB3_CLK_FACTOR_N(reg);
154422652d99Suaa 		return freq / (m * n);
154522652d99Suaa 	case H616_CLK_APB2:
154622652d99Suaa 		/* XXX Controlled by a MUX. */
154722652d99Suaa 		return 24000000;
154822652d99Suaa 	}
154922652d99Suaa 
155022652d99Suaa 	printf("%s: 0x%08x\n", __func__, idx);
155122652d99Suaa 	return 0;
155222652d99Suaa }
155322652d99Suaa 
155422652d99Suaa uint32_t
sxiccmu_h616_r_get_frequency(struct sxiccmu_softc * sc,uint32_t idx)155522652d99Suaa sxiccmu_h616_r_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
155622652d99Suaa {
155722652d99Suaa 	switch (idx) {
155822652d99Suaa 	case H616_R_CLK_APB2:
155922652d99Suaa 		/* XXX Controlled by a MUX. */
156022652d99Suaa 		return 24000000;
15618b22851bSkettenis 	}
15628b22851bSkettenis 
15638b22851bSkettenis 	printf("%s: 0x%08x\n", __func__, idx);
15648b22851bSkettenis 	return 0;
15658b22851bSkettenis }
15668b22851bSkettenis 
15678b22851bSkettenis uint32_t
sxiccmu_r40_get_frequency(struct sxiccmu_softc * sc,uint32_t idx)1568a6d148daSkettenis sxiccmu_r40_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
1569a6d148daSkettenis {
157029e54e85Skettenis 	uint32_t parent;
157129e54e85Skettenis 	uint32_t reg, div;
157229e54e85Skettenis 
1573a6d148daSkettenis 	switch (idx) {
157429e54e85Skettenis 	case R40_CLK_LOSC:
157529e54e85Skettenis 		return clock_get_frequency(sc->sc_node, "losc");
157629e54e85Skettenis 	case R40_CLK_HOSC:
157729e54e85Skettenis 		return clock_get_frequency(sc->sc_node, "hosc");
1578a6d148daSkettenis 	case R40_CLK_PLL_PERIPH0:
1579a6d148daSkettenis 		/* Not hardcoded, but recommended. */
1580a6d148daSkettenis 		return 600000000;
1581a6d148daSkettenis 	case R40_CLK_PLL_PERIPH0_2X:
158229e54e85Skettenis 		return sxiccmu_r40_get_frequency(sc, R40_CLK_PLL_PERIPH0) * 2;
158329e54e85Skettenis 	case R40_CLK_AHB1:
158429e54e85Skettenis 		reg = SXIREAD4(sc, CCU_AHB1_APB1_CFG_REG);
158529e54e85Skettenis 		div = CCU_AHB1_CLK_DIV_RATIO(reg);
158629e54e85Skettenis 		switch (reg & CCU_AHB1_CLK_SRC_SEL) {
158729e54e85Skettenis 		case CCU_AHB1_CLK_SRC_SEL_LOSC:
158829e54e85Skettenis 			parent = R40_CLK_LOSC;
158929e54e85Skettenis 			break;
159029e54e85Skettenis 		case CCU_AHB1_CLK_SRC_SEL_OSC24M:
159129e54e85Skettenis 			parent = R40_CLK_HOSC;
159229e54e85Skettenis 			break;
159329e54e85Skettenis 		case CCU_AHB1_CLK_SRC_SEL_AXI:
159429e54e85Skettenis 			parent = R40_CLK_AXI;
159529e54e85Skettenis 			break;
159629e54e85Skettenis 		case CCU_AHB1_CLK_SRC_SEL_PERIPH0:
159729e54e85Skettenis 			parent = R40_CLK_PLL_PERIPH0;
159829e54e85Skettenis 			div *= CCU_AHB1_PRE_DIV(reg);
159929e54e85Skettenis 			break;
160029e54e85Skettenis 		}
160129e54e85Skettenis 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
1602a6d148daSkettenis 	case R40_CLK_APB2:
1603a6d148daSkettenis 		/* XXX Controlled by a MUX. */
1604a6d148daSkettenis 		return 24000000;
1605a6d148daSkettenis 	}
1606a6d148daSkettenis 
1607a6d148daSkettenis 	printf("%s: 0x%08x\n", __func__, idx);
1608a6d148daSkettenis 	return 0;
1609a6d148daSkettenis }
1610a6d148daSkettenis 
1611a6d148daSkettenis uint32_t
sxiccmu_v3s_get_frequency(struct sxiccmu_softc * sc,uint32_t idx)16123fb3ba8fSkettenis sxiccmu_v3s_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
16133fb3ba8fSkettenis {
16143fb3ba8fSkettenis 	uint32_t parent;
16153fb3ba8fSkettenis 	uint32_t reg, div;
16163fb3ba8fSkettenis 
16173fb3ba8fSkettenis 	switch (idx) {
16183fb3ba8fSkettenis 	case V3S_CLK_LOSC:
16193fb3ba8fSkettenis 		return clock_get_frequency(sc->sc_node, "losc");
16203fb3ba8fSkettenis 	case V3S_CLK_HOSC:
16213fb3ba8fSkettenis 		return clock_get_frequency(sc->sc_node, "hosc");
16223fb3ba8fSkettenis 	case V3S_CLK_PLL_PERIPH0:
16233fb3ba8fSkettenis 		/* Not hardcoded, but recommended. */
16243fb3ba8fSkettenis 		return 600000000;
16253fb3ba8fSkettenis 	case V3S_CLK_APB2:
16263fb3ba8fSkettenis 		/* XXX Controlled by a MUX. */
16273fb3ba8fSkettenis 		return 24000000;
16283fb3ba8fSkettenis 	case V3S_CLK_AHB1:
16293fb3ba8fSkettenis 		reg = SXIREAD4(sc, CCU_AHB1_APB1_CFG_REG);
16303fb3ba8fSkettenis 		div = CCU_AHB1_CLK_DIV_RATIO(reg);
16313fb3ba8fSkettenis 		switch (reg & CCU_AHB1_CLK_SRC_SEL) {
16323fb3ba8fSkettenis 		case CCU_AHB1_CLK_SRC_SEL_LOSC:
16333fb3ba8fSkettenis 			parent = V3S_CLK_LOSC;
16343fb3ba8fSkettenis 			break;
16353fb3ba8fSkettenis 		case CCU_AHB1_CLK_SRC_SEL_OSC24M:
16363fb3ba8fSkettenis 			parent = V3S_CLK_HOSC;
16373fb3ba8fSkettenis 			break;
16383fb3ba8fSkettenis 		case CCU_AHB1_CLK_SRC_SEL_AXI:
16393fb3ba8fSkettenis 			parent = V3S_CLK_AXI;
16403fb3ba8fSkettenis 			break;
16413fb3ba8fSkettenis 		case CCU_AHB1_CLK_SRC_SEL_PERIPH0:
16423fb3ba8fSkettenis 			parent = V3S_CLK_PLL_PERIPH0;
16433fb3ba8fSkettenis 			div *= CCU_AHB1_PRE_DIV(reg);
16443fb3ba8fSkettenis 			break;
16453fb3ba8fSkettenis 		default:
16463fb3ba8fSkettenis 			return 0;
16473fb3ba8fSkettenis 		}
16483fb3ba8fSkettenis 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
16493fb3ba8fSkettenis 	case V3S_CLK_AHB2:
16503fb3ba8fSkettenis 		reg = SXIREAD4(sc, CCU_AHB2_CFG_REG);
16513fb3ba8fSkettenis 		switch (reg & CCU_AHB2_CLK_CFG) {
16523fb3ba8fSkettenis 		case 0:
16533fb3ba8fSkettenis 			parent = V3S_CLK_AHB1;
16543fb3ba8fSkettenis 			div = 1;
16553fb3ba8fSkettenis 			break;
16563fb3ba8fSkettenis 		case 1:
16573fb3ba8fSkettenis 			parent = V3S_CLK_PLL_PERIPH0;
16583fb3ba8fSkettenis 			div = 2;
16593fb3ba8fSkettenis 			break;
16603fb3ba8fSkettenis 		default:
16613fb3ba8fSkettenis 			return 0;
16623fb3ba8fSkettenis 		}
16633fb3ba8fSkettenis 		return sxiccmu_ccu_get_frequency(sc, &parent) / div;
16643fb3ba8fSkettenis 	}
16653fb3ba8fSkettenis 
16663fb3ba8fSkettenis 	printf("%s: 0x%08x\n", __func__, idx);
16673fb3ba8fSkettenis 	return 0;
16683fb3ba8fSkettenis }
16693fb3ba8fSkettenis 
16703fb3ba8fSkettenis uint32_t
sxiccmu_nop_get_frequency(struct sxiccmu_softc * sc,uint32_t idx)16712c064ff8Skettenis sxiccmu_nop_get_frequency(struct sxiccmu_softc *sc, uint32_t idx)
16722c064ff8Skettenis {
16732c064ff8Skettenis 	printf("%s: 0x%08x\n", __func__, idx);
16742c064ff8Skettenis 	return 0;
16752c064ff8Skettenis }
16762c064ff8Skettenis 
16770ea1c705Spatrick int
sxiccmu_ccu_set_frequency(void * cookie,uint32_t * cells,uint32_t freq)16780ea1c705Spatrick sxiccmu_ccu_set_frequency(void *cookie, uint32_t *cells, uint32_t freq)
16790ea1c705Spatrick {
16800ea1c705Spatrick 	struct sxiccmu_softc *sc = cookie;
16810ea1c705Spatrick 	uint32_t idx = cells[0];
16820ea1c705Spatrick 
16830ea1c705Spatrick 	return sc->sc_set_frequency(sc, idx, freq);
16840ea1c705Spatrick }
16850ea1c705Spatrick 
16860ea1c705Spatrick int
sxiccmu_a10_set_frequency(struct sxiccmu_softc * sc,uint32_t idx,uint32_t freq)1687e6e86968Skettenis sxiccmu_a10_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1688e6e86968Skettenis {
1689e6e86968Skettenis 	struct sxiccmu_clock clock;
1690e6e86968Skettenis 	uint32_t parent, parent_freq;
1691193b1cd6Skettenis 	uint32_t reg;
1692193b1cd6Skettenis 	int k, n;
1693193b1cd6Skettenis 	int error;
1694e6e86968Skettenis 
1695e6e86968Skettenis 	switch (idx) {
1696193b1cd6Skettenis 	case A10_CLK_PLL_CORE:
1697193b1cd6Skettenis 		k = 1; n = 32;
1698193b1cd6Skettenis 		while (k <= 4 && (24000000 * n * k) < freq)
1699193b1cd6Skettenis 			k++;
1700193b1cd6Skettenis 		while (n >= 1 && (24000000 * n * k) > freq)
1701193b1cd6Skettenis 			n--;
1702193b1cd6Skettenis 
1703193b1cd6Skettenis 		reg = SXIREAD4(sc, A10_PLL1_CFG_REG);
1704193b1cd6Skettenis 		reg &= ~A10_PLL1_OUT_EXT_DIVP_MASK;
1705193b1cd6Skettenis 		reg &= ~A10_PLL1_FACTOR_N_MASK;
1706193b1cd6Skettenis 		reg &= ~A10_PLL1_FACTOR_K_MASK;
1707193b1cd6Skettenis 		reg &= ~A10_PLL1_FACTOR_M_MASK;
1708193b1cd6Skettenis 		reg |= (n << A10_PLL1_FACTOR_N_SHIFT);
1709193b1cd6Skettenis 		reg |= ((k - 1) << A10_PLL1_FACTOR_K_SHIFT);
1710193b1cd6Skettenis 		SXIWRITE4(sc, A10_PLL1_CFG_REG, reg);
1711193b1cd6Skettenis 
1712193b1cd6Skettenis 		/* No need to wait PLL to lock? */
1713193b1cd6Skettenis 
1714193b1cd6Skettenis 		return 0;
1715193b1cd6Skettenis 	case A10_CLK_CPU:
1716193b1cd6Skettenis 		/* Switch to 24 MHz clock. */
1717193b1cd6Skettenis 		reg = SXIREAD4(sc, A10_CPU_AHB_APB0_CFG_REG);
1718193b1cd6Skettenis 		reg &= ~A10_CPU_CLK_SRC_SEL;
1719193b1cd6Skettenis 		reg |= A10_CPU_CLK_SRC_SEL_OSC24M;
1720193b1cd6Skettenis 		SXIWRITE4(sc, A10_CPU_AHB_APB0_CFG_REG, reg);
1721193b1cd6Skettenis 
1722193b1cd6Skettenis 		error = sxiccmu_a10_set_frequency(sc, A10_CLK_PLL_CORE, freq);
1723193b1cd6Skettenis 
1724193b1cd6Skettenis 		/* Switch back to PLL. */
1725193b1cd6Skettenis 		reg = SXIREAD4(sc, A10_CPU_AHB_APB0_CFG_REG);
1726193b1cd6Skettenis 		reg &= ~A10_CPU_CLK_SRC_SEL;
1727193b1cd6Skettenis 		reg |= A10_CPU_CLK_SRC_SEL_PLL1;
1728193b1cd6Skettenis 		SXIWRITE4(sc, A10_CPU_AHB_APB0_CFG_REG, reg);
1729193b1cd6Skettenis 		return error;
1730e6e86968Skettenis 	case A10_CLK_MMC0:
1731e6e86968Skettenis 	case A10_CLK_MMC1:
1732e6e86968Skettenis 	case A10_CLK_MMC2:
1733e6e86968Skettenis 	case A10_CLK_MMC3:
1734e6e86968Skettenis 		clock.sc_iot = sc->sc_iot;
1735e6e86968Skettenis 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
1736e6e86968Skettenis 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
1737e6e86968Skettenis 		parent = A10_CLK_PLL_PERIPH;
1738e6e86968Skettenis 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
1739e6e86968Skettenis 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
1740e6e86968Skettenis 	}
1741e6e86968Skettenis 
1742e6e86968Skettenis 	printf("%s: 0x%08x\n", __func__, idx);
1743e6e86968Skettenis 	return -1;
1744e6e86968Skettenis }
1745e6e86968Skettenis 
1746e6e86968Skettenis int
sxiccmu_a10s_set_frequency(struct sxiccmu_softc * sc,uint32_t idx,uint32_t freq)1747199786d9Skettenis sxiccmu_a10s_set_frequency(struct sxiccmu_softc *sc, uint32_t idx,
17484e623b4aSderaadt     uint32_t freq)
1749199786d9Skettenis {
1750199786d9Skettenis 	struct sxiccmu_clock clock;
1751199786d9Skettenis 	uint32_t parent, parent_freq;
1752199786d9Skettenis 	uint32_t reg;
1753199786d9Skettenis 	int k, n;
1754199786d9Skettenis 	int error;
1755199786d9Skettenis 
1756199786d9Skettenis 	switch (idx) {
1757199786d9Skettenis 	case A10S_CLK_PLL_CORE:
1758199786d9Skettenis 		k = 1; n = 32;
1759199786d9Skettenis 		while (k <= 4 && (24000000 * n * k) < freq)
1760199786d9Skettenis 			k++;
1761199786d9Skettenis 		while (n >= 1 && (24000000 * n * k) > freq)
1762199786d9Skettenis 			n--;
1763199786d9Skettenis 
1764199786d9Skettenis 		reg = SXIREAD4(sc, A10_PLL1_CFG_REG);
1765199786d9Skettenis 		reg &= ~A10_PLL1_OUT_EXT_DIVP_MASK;
1766199786d9Skettenis 		reg &= ~A10_PLL1_FACTOR_N_MASK;
1767199786d9Skettenis 		reg &= ~A10_PLL1_FACTOR_K_MASK;
1768199786d9Skettenis 		reg &= ~A10_PLL1_FACTOR_M_MASK;
1769199786d9Skettenis 		reg |= (n << A10_PLL1_FACTOR_N_SHIFT);
1770199786d9Skettenis 		reg |= ((k - 1) << A10_PLL1_FACTOR_K_SHIFT);
1771199786d9Skettenis 		SXIWRITE4(sc, A10_PLL1_CFG_REG, reg);
1772199786d9Skettenis 
1773199786d9Skettenis 		/* No need to wait PLL to lock? */
1774199786d9Skettenis 
1775199786d9Skettenis 		return 0;
1776199786d9Skettenis 	case A10S_CLK_CPU:
1777199786d9Skettenis 		/* Switch to 24 MHz clock. */
1778199786d9Skettenis 		reg = SXIREAD4(sc, A10_CPU_AHB_APB0_CFG_REG);
1779199786d9Skettenis 		reg &= ~A10_CPU_CLK_SRC_SEL;
1780199786d9Skettenis 		reg |= A10_CPU_CLK_SRC_SEL_OSC24M;
1781199786d9Skettenis 		SXIWRITE4(sc, A10_CPU_AHB_APB0_CFG_REG, reg);
1782199786d9Skettenis 
1783199786d9Skettenis 		error = sxiccmu_a10s_set_frequency(sc, A10S_CLK_PLL_CORE, freq);
1784199786d9Skettenis 
1785199786d9Skettenis 		/* Switch back to PLL. */
1786199786d9Skettenis 		reg = SXIREAD4(sc, A10_CPU_AHB_APB0_CFG_REG);
1787199786d9Skettenis 		reg &= ~A10_CPU_CLK_SRC_SEL;
1788199786d9Skettenis 		reg |= A10_CPU_CLK_SRC_SEL_PLL1;
1789199786d9Skettenis 		SXIWRITE4(sc, A10_CPU_AHB_APB0_CFG_REG, reg);
1790199786d9Skettenis 		return error;
1791199786d9Skettenis 	case A10S_CLK_MMC0:
1792199786d9Skettenis 	case A10S_CLK_MMC1:
1793199786d9Skettenis 	case A10S_CLK_MMC2:
1794199786d9Skettenis 		clock.sc_iot = sc->sc_iot;
1795199786d9Skettenis 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
1796199786d9Skettenis 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
1797199786d9Skettenis 		parent = A10S_CLK_PLL_PERIPH;
1798199786d9Skettenis 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
1799199786d9Skettenis 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
1800199786d9Skettenis 	}
1801199786d9Skettenis 
1802199786d9Skettenis 	printf("%s: 0x%08x\n", __func__, idx);
1803199786d9Skettenis 	return -1;
1804199786d9Skettenis }
1805199786d9Skettenis 
1806199786d9Skettenis int
sxiccmu_a23_set_frequency(struct sxiccmu_softc * sc,uint32_t idx,uint32_t freq)1807f0a8b882Skevlo sxiccmu_a23_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1808f0a8b882Skevlo {
1809f0a8b882Skevlo 	struct sxiccmu_clock clock;
1810f0a8b882Skevlo 	uint32_t parent, parent_freq;
1811f0a8b882Skevlo 
1812f0a8b882Skevlo 	switch (idx) {
1813f0a8b882Skevlo 	case A23_CLK_MMC0:
1814f0a8b882Skevlo 	case A23_CLK_MMC1:
1815f0a8b882Skevlo 	case A23_CLK_MMC2:
1816f0a8b882Skevlo 		clock.sc_iot = sc->sc_iot;
1817f0a8b882Skevlo 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
1818f0a8b882Skevlo 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
1819f0a8b882Skevlo 		parent = A23_CLK_PLL_PERIPH;
1820f0a8b882Skevlo 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
1821f0a8b882Skevlo 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
1822f0a8b882Skevlo 	}
1823f0a8b882Skevlo 
1824f0a8b882Skevlo 	printf("%s: 0x%08x\n", __func__, idx);
1825f0a8b882Skevlo 	return -1;
1826f0a8b882Skevlo }
1827f0a8b882Skevlo 
1828f0a8b882Skevlo int
sxiccmu_a64_set_frequency(struct sxiccmu_softc * sc,uint32_t idx,uint32_t freq)18290ea1c705Spatrick sxiccmu_a64_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
18300ea1c705Spatrick {
18310ea1c705Spatrick 	struct sxiccmu_clock clock;
18320ea1c705Spatrick 	uint32_t parent, parent_freq;
1833bced15f9Skettenis 	uint32_t reg;
1834bced15f9Skettenis 	int k, n;
1835bced15f9Skettenis 	int error;
18360ea1c705Spatrick 
18370ea1c705Spatrick 	switch (idx) {
1838bced15f9Skettenis 	case A64_CLK_PLL_CPUX:
1839bced15f9Skettenis 		k = 1; n = 32;
1840bced15f9Skettenis 		while (k <= 4 && (24000000 * n * k) < freq)
1841bced15f9Skettenis 			k++;
1842bced15f9Skettenis 		while (n >= 1 && (24000000 * n * k) > freq)
1843bced15f9Skettenis 			n--;
1844bced15f9Skettenis 
1845bced15f9Skettenis 		reg = SXIREAD4(sc, A64_PLL_CPUX_CTRL_REG);
1846bced15f9Skettenis 		reg &= ~A64_PLL_CPUX_OUT_EXT_DIVP_MASK;
1847bced15f9Skettenis 		reg &= ~A64_PLL_CPUX_FACTOR_N_MASK;
1848bced15f9Skettenis 		reg &= ~A64_PLL_CPUX_FACTOR_K_MASK;
1849bced15f9Skettenis 		reg &= ~A64_PLL_CPUX_FACTOR_M_MASK;
1850bced15f9Skettenis 		reg |= ((n - 1) << A64_PLL_CPUX_FACTOR_N_SHIFT);
1851bced15f9Skettenis 		reg |= ((k - 1) << A64_PLL_CPUX_FACTOR_K_SHIFT);
1852bced15f9Skettenis 		SXIWRITE4(sc, A64_PLL_CPUX_CTRL_REG, reg);
1853bced15f9Skettenis 
1854bced15f9Skettenis 		/* Wait for PLL to lock. */
1855bced15f9Skettenis 		while ((SXIREAD4(sc, A64_PLL_CPUX_CTRL_REG) &
1856bced15f9Skettenis 		    A64_PLL_CPUX_LOCK) == 0) {
1857bced15f9Skettenis 			delay(200);
1858bced15f9Skettenis 		}
1859bced15f9Skettenis 
1860bced15f9Skettenis 		return 0;
1861bced15f9Skettenis 	case A64_CLK_CPUX:
1862bced15f9Skettenis 		/* Switch to 24 MHz clock. */
1863bced15f9Skettenis 		reg = SXIREAD4(sc, A64_CPUX_AXI_CFG_REG);
1864bced15f9Skettenis 		reg &= ~A64_CPUX_CLK_SRC_SEL;
1865bced15f9Skettenis 		reg |= A64_CPUX_CLK_SRC_SEL_OSC24M;
1866bced15f9Skettenis 		SXIWRITE4(sc, A64_CPUX_AXI_CFG_REG, reg);
1867bced15f9Skettenis 
1868bced15f9Skettenis 		error = sxiccmu_a64_set_frequency(sc, A64_CLK_PLL_CPUX, freq);
1869bced15f9Skettenis 
1870bced15f9Skettenis 		/* Switch back to PLL. */
1871bced15f9Skettenis 		reg = SXIREAD4(sc, A64_CPUX_AXI_CFG_REG);
1872bced15f9Skettenis 		reg &= ~A64_CPUX_CLK_SRC_SEL;
1873bced15f9Skettenis 		reg |= A64_CPUX_CLK_SRC_SEL_PLL_CPUX;
1874bced15f9Skettenis 		SXIWRITE4(sc, A64_CPUX_AXI_CFG_REG, reg);
1875bced15f9Skettenis 		return error;
18760ea1c705Spatrick 	case A64_CLK_MMC0:
18770ea1c705Spatrick 	case A64_CLK_MMC1:
18780ea1c705Spatrick 	case A64_CLK_MMC2:
18790ea1c705Spatrick 		clock.sc_iot = sc->sc_iot;
18800ea1c705Spatrick 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
18810ea1c705Spatrick 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
18820ea1c705Spatrick 		parent = A64_CLK_PLL_PERIPH0_2X;
18830ea1c705Spatrick 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
18840ea1c705Spatrick 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
18850ea1c705Spatrick 	}
18860ea1c705Spatrick 
18870ea1c705Spatrick 	printf("%s: 0x%08x\n", __func__, idx);
18880ea1c705Spatrick 	return -1;
18890ea1c705Spatrick }
18900ea1c705Spatrick 
18910ea1c705Spatrick int
sxiccmu_a80_set_frequency(struct sxiccmu_softc * sc,uint32_t idx,uint32_t freq)1892d526c0edSkettenis sxiccmu_a80_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
1893d526c0edSkettenis {
1894d526c0edSkettenis 	struct sxiccmu_clock clock;
1895d526c0edSkettenis 	uint32_t parent, parent_freq;
1896d526c0edSkettenis 
1897d526c0edSkettenis 	switch (idx) {
1898d526c0edSkettenis 	case A80_CLK_MMC0:
1899d526c0edSkettenis 	case A80_CLK_MMC1:
1900d526c0edSkettenis 	case A80_CLK_MMC2:
1901d526c0edSkettenis 		clock.sc_iot = sc->sc_iot;
1902d526c0edSkettenis 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
1903d526c0edSkettenis 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
1904d526c0edSkettenis 		parent = A80_CLK_PLL_PERIPH0;
1905d526c0edSkettenis 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
1906d526c0edSkettenis 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
1907d526c0edSkettenis 	}
1908d526c0edSkettenis 
1909d526c0edSkettenis 	printf("%s: 0x%08x\n", __func__, idx);
1910d526c0edSkettenis 	return -1;
1911d526c0edSkettenis }
1912d526c0edSkettenis 
19134718ccb1Skettenis #define D1_SMHC0_CLK_REG		0x0830
19144718ccb1Skettenis #define D1_SMHC1_CLK_REG		0x0834
19154718ccb1Skettenis #define D1_SMHC2_CLK_REG		0x0838
19164718ccb1Skettenis #define D1_SMHC_CLK_SRC_SEL			(0x3 << 24)
19174718ccb1Skettenis #define D1_SMHC_CLK_SRC_SEL_HOSC		(0x0 << 24)
19184718ccb1Skettenis #define D1_SMHC_CLK_SRC_SEL_PLL_PERIPH0		(0x1 << 24)
19194718ccb1Skettenis #define D1_SMHC_FACTOR_N_MASK			(0x3 << 8)
19204718ccb1Skettenis #define D1_SMHC_FACTOR_N_SHIFT			8
19214718ccb1Skettenis #define D1_SMHC_FACTOR_M_MASK			(0xf << 0)
19224718ccb1Skettenis #define D1_SMHC_FACTOR_M_SHIFT			0
19234718ccb1Skettenis 
19244718ccb1Skettenis int
sxiccmu_d1_mmc_set_frequency(struct sxiccmu_softc * sc,bus_size_t offset,uint32_t freq)19254718ccb1Skettenis sxiccmu_d1_mmc_set_frequency(struct sxiccmu_softc *sc, bus_size_t offset,
19264718ccb1Skettenis     uint32_t freq)
19274718ccb1Skettenis {
19284718ccb1Skettenis 	uint32_t parent_freq;
19294718ccb1Skettenis 	uint32_t reg, m, n;
19304718ccb1Skettenis 	uint32_t clk_src;
19314718ccb1Skettenis 
19324718ccb1Skettenis 	switch (freq) {
19334718ccb1Skettenis 	case 400000:
19344718ccb1Skettenis 		n = 2, m = 15;
19354718ccb1Skettenis 		clk_src = D1_SMHC_CLK_SRC_SEL_HOSC;
19364718ccb1Skettenis 		break;
19374718ccb1Skettenis 	case 20000000:
19384718ccb1Skettenis 	case 25000000:
19394718ccb1Skettenis 	case 26000000:
19404718ccb1Skettenis 	case 50000000:
19414718ccb1Skettenis 	case 52000000:
19424718ccb1Skettenis 		n = 0, m = 0;
19434718ccb1Skettenis 		clk_src = D1_SMHC_CLK_SRC_SEL_PLL_PERIPH0;
19444718ccb1Skettenis 		parent_freq =
19454718ccb1Skettenis 		    sxiccmu_d1_get_frequency(sc, D1_CLK_PLL_PERIPH0);
19464718ccb1Skettenis 		while ((parent_freq / (1 << n) / 16) > freq)
19474718ccb1Skettenis 			n++;
19484718ccb1Skettenis 		while ((parent_freq / (1 << n) / (m + 1)) > freq)
19494718ccb1Skettenis 			m++;
19504718ccb1Skettenis 		break;
19514718ccb1Skettenis 	default:
19524718ccb1Skettenis 		return -1;
19534718ccb1Skettenis 	}
19544718ccb1Skettenis 
19554718ccb1Skettenis 	reg = SXIREAD4(sc, offset);
19564718ccb1Skettenis 	reg &= ~D1_SMHC_CLK_SRC_SEL;
19574718ccb1Skettenis 	reg |= clk_src;
19584718ccb1Skettenis 	reg &= ~D1_SMHC_FACTOR_N_MASK;
19594718ccb1Skettenis 	reg |= n << D1_SMHC_FACTOR_N_SHIFT;
19604718ccb1Skettenis 	reg &= ~D1_SMHC_FACTOR_M_MASK;
19614718ccb1Skettenis 	reg |= m << D1_SMHC_FACTOR_M_SHIFT;
19624718ccb1Skettenis 	SXIWRITE4(sc, offset, reg);
19634718ccb1Skettenis 
19644718ccb1Skettenis 	return 0;
19654718ccb1Skettenis }
19664718ccb1Skettenis 
1967d526c0edSkettenis int
sxiccmu_d1_set_frequency(struct sxiccmu_softc * sc,uint32_t idx,uint32_t freq)19684e48f70dSkettenis sxiccmu_d1_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
19694e48f70dSkettenis {
19704718ccb1Skettenis 	switch (idx) {
19714718ccb1Skettenis 	case D1_CLK_MMC0:
19724718ccb1Skettenis 		return sxiccmu_d1_mmc_set_frequency(sc, D1_SMHC0_CLK_REG, freq);
19734718ccb1Skettenis 	case D1_CLK_MMC1:
19744718ccb1Skettenis 		return sxiccmu_d1_mmc_set_frequency(sc, D1_SMHC1_CLK_REG, freq);
19754718ccb1Skettenis 	case D1_CLK_MMC2:
19764718ccb1Skettenis 		return sxiccmu_d1_mmc_set_frequency(sc, D1_SMHC2_CLK_REG, freq);
19774718ccb1Skettenis 	}
19784718ccb1Skettenis 
19794e48f70dSkettenis 	printf("%s: 0x%08x\n", __func__, idx);
19804e48f70dSkettenis 	return -1;
19814e48f70dSkettenis }
19824e48f70dSkettenis 
19834e48f70dSkettenis int
sxiccmu_h3_set_frequency(struct sxiccmu_softc * sc,uint32_t idx,uint32_t freq)19840ea1c705Spatrick sxiccmu_h3_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
19850ea1c705Spatrick {
19860ea1c705Spatrick 	struct sxiccmu_clock clock;
19870ea1c705Spatrick 	uint32_t parent, parent_freq;
19889424095dSuaa 	uint32_t reg, lock_time;
1989f1089a02Skettenis 	int k, n;
1990f1089a02Skettenis 	int error;
19910ea1c705Spatrick 
19920ea1c705Spatrick 	switch (idx) {
1993f1089a02Skettenis 	case H3_CLK_PLL_CPUX:
1994f1089a02Skettenis 		k = 1; n = 32;
1995f1089a02Skettenis 		while (k <= 4 && (24000000 * n * k) < freq)
1996f1089a02Skettenis 			k++;
1997f1089a02Skettenis 		while (n >= 1 && (24000000 * n * k) > freq)
1998f1089a02Skettenis 			n--;
1999f1089a02Skettenis 
20009424095dSuaa 		/* Gate the PLL first */
2001f1089a02Skettenis 		reg = SXIREAD4(sc, H3_PLL_CPUX_CTRL_REG);
20029424095dSuaa 		reg &= ~H3_PLL_CPUX_ENABLE;
20039424095dSuaa 		SXIWRITE4(sc, H3_PLL_CPUX_CTRL_REG, reg);
20049424095dSuaa 
20059424095dSuaa 		/* Set factors and external divider. */
2006f1089a02Skettenis 		reg &= ~H3_PLL_CPUX_OUT_EXT_DIVP_MASK;
2007f1089a02Skettenis 		reg &= ~H3_PLL_CPUX_FACTOR_N_MASK;
2008f1089a02Skettenis 		reg &= ~H3_PLL_CPUX_FACTOR_K_MASK;
2009f1089a02Skettenis 		reg &= ~H3_PLL_CPUX_FACTOR_M_MASK;
2010f1089a02Skettenis 		reg |= ((n - 1) << H3_PLL_CPUX_FACTOR_N_SHIFT);
2011f1089a02Skettenis 		reg |= ((k - 1) << H3_PLL_CPUX_FACTOR_K_SHIFT);
2012f1089a02Skettenis 		SXIWRITE4(sc, H3_PLL_CPUX_CTRL_REG, reg);
2013f1089a02Skettenis 
20149424095dSuaa 		/* Ungate the PLL */
20159424095dSuaa 		reg |= H3_PLL_CPUX_ENABLE;
20169424095dSuaa 		SXIWRITE4(sc, H3_PLL_CPUX_CTRL_REG, reg);
20179424095dSuaa 
20189424095dSuaa 		/* Wait for PLL to lock. (LOCK flag is unreliable) */
20199424095dSuaa 		lock_time = SXIREAD4(sc, H3_PLL_STABLE_TIME_REG1);
20209424095dSuaa 		delay(H3_PLL_STABLE_TIME_REG1_TIME(lock_time));
2021f1089a02Skettenis 
2022f1089a02Skettenis 		return 0;
2023f1089a02Skettenis 	case H3_CLK_CPUX:
2024f1089a02Skettenis 		/* Switch to 24 MHz clock. */
2025f1089a02Skettenis 		reg = SXIREAD4(sc, H3_CPUX_AXI_CFG_REG);
2026f1089a02Skettenis 		reg &= ~H3_CPUX_CLK_SRC_SEL;
2027f1089a02Skettenis 		reg |= H3_CPUX_CLK_SRC_SEL_OSC24M;
2028f1089a02Skettenis 		SXIWRITE4(sc, H3_CPUX_AXI_CFG_REG, reg);
20299424095dSuaa 		/* Must wait at least 8 cycles of the current clock. */
20309424095dSuaa 		delay(1);
2031f1089a02Skettenis 
2032f1089a02Skettenis 		error = sxiccmu_h3_set_frequency(sc, H3_CLK_PLL_CPUX, freq);
2033f1089a02Skettenis 
2034f1089a02Skettenis 		/* Switch back to PLL. */
2035f1089a02Skettenis 		reg = SXIREAD4(sc, H3_CPUX_AXI_CFG_REG);
2036f1089a02Skettenis 		reg &= ~H3_CPUX_CLK_SRC_SEL;
2037f1089a02Skettenis 		reg |= H3_CPUX_CLK_SRC_SEL_PLL_CPUX;
2038f1089a02Skettenis 		SXIWRITE4(sc, H3_CPUX_AXI_CFG_REG, reg);
20399424095dSuaa 		/* Must wait at least 8 cycles of the current clock. */
20409424095dSuaa 		delay(1);
2041f1089a02Skettenis 		return error;
20420ea1c705Spatrick 	case H3_CLK_MMC0:
20430ea1c705Spatrick 	case H3_CLK_MMC1:
20440ea1c705Spatrick 	case H3_CLK_MMC2:
20450ea1c705Spatrick 		clock.sc_iot = sc->sc_iot;
20460ea1c705Spatrick 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
20470ea1c705Spatrick 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
20480ea1c705Spatrick 		parent = H3_CLK_PLL_PERIPH0;
20490ea1c705Spatrick 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
20500ea1c705Spatrick 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
20510ea1c705Spatrick 	}
20520ea1c705Spatrick 
20530ea1c705Spatrick 	printf("%s: 0x%08x\n", __func__, idx);
20540ea1c705Spatrick 	return -1;
20550ea1c705Spatrick }
20560ea1c705Spatrick 
20578b22851bSkettenis #define H6_SMHC0_CLK_REG		0x0830
20588b22851bSkettenis #define H6_SMHC1_CLK_REG		0x0834
20598b22851bSkettenis #define H6_SMHC2_CLK_REG		0x0838
20608b22851bSkettenis #define H6_SMHC_CLK_SRC_SEL			(0x3 << 24)
20618b22851bSkettenis #define H6_SMHC_CLK_SRC_SEL_OSC24M		(0x0 << 24)
20628b22851bSkettenis #define H6_SMHC_CLK_SRC_SEL_PLL_PERIPH0_2X	(0x1 << 24)
20638b22851bSkettenis #define H6_SMHC_FACTOR_N_MASK			(0x3 << 8)
20648b22851bSkettenis #define H6_SMHC_FACTOR_N_SHIFT			8
20658b22851bSkettenis #define H6_SMHC_FACTOR_M_MASK			(0xf << 0)
20668b22851bSkettenis #define H6_SMHC_FACTOR_M_SHIFT			0
20678b22851bSkettenis 
20688b22851bSkettenis int
sxiccmu_h6_mmc_set_frequency(struct sxiccmu_softc * sc,bus_size_t offset,uint32_t freq,uint32_t parent_freq)20698b22851bSkettenis sxiccmu_h6_mmc_set_frequency(struct sxiccmu_softc *sc, bus_size_t offset,
207022652d99Suaa     uint32_t freq, uint32_t parent_freq)
20718b22851bSkettenis {
20728b22851bSkettenis 	uint32_t reg, m, n;
20738b22851bSkettenis 	uint32_t clk_src;
20748b22851bSkettenis 
20758b22851bSkettenis 	switch (freq) {
20768b22851bSkettenis 	case 400000:
20778b22851bSkettenis 		n = 2, m = 15;
20788b22851bSkettenis 		clk_src = H6_SMHC_CLK_SRC_SEL_OSC24M;
20798b22851bSkettenis 		break;
20808b22851bSkettenis 	case 20000000:
20818b22851bSkettenis 	case 25000000:
20828b22851bSkettenis 	case 26000000:
20838b22851bSkettenis 	case 50000000:
20848b22851bSkettenis 	case 52000000:
20858b22851bSkettenis 		n = 0, m = 0;
20868b22851bSkettenis 		clk_src = H6_SMHC_CLK_SRC_SEL_PLL_PERIPH0_2X;
20878b22851bSkettenis 		while ((parent_freq / (1 << n) / 16) > freq)
20888b22851bSkettenis 			n++;
20898b22851bSkettenis 		while ((parent_freq / (1 << n) / (m + 1)) > freq)
20908b22851bSkettenis 			m++;
20918b22851bSkettenis 		break;
20928b22851bSkettenis 	default:
20938b22851bSkettenis 		return -1;
20948b22851bSkettenis 	}
20958b22851bSkettenis 
20968b22851bSkettenis 	reg = SXIREAD4(sc, offset);
20978b22851bSkettenis 	reg &= ~H6_SMHC_CLK_SRC_SEL;
20988b22851bSkettenis 	reg |= clk_src;
20998b22851bSkettenis 	reg &= ~H6_SMHC_FACTOR_N_MASK;
21008b22851bSkettenis 	reg |= n << H6_SMHC_FACTOR_N_SHIFT;
21018b22851bSkettenis 	reg &= ~H6_SMHC_FACTOR_M_MASK;
21028b22851bSkettenis 	reg |= m << H6_SMHC_FACTOR_M_SHIFT;
21038b22851bSkettenis 	SXIWRITE4(sc, offset, reg);
21048b22851bSkettenis 
21058b22851bSkettenis 	return 0;
21068b22851bSkettenis }
21078b22851bSkettenis 
21088b22851bSkettenis int
sxiccmu_h6_set_frequency(struct sxiccmu_softc * sc,uint32_t idx,uint32_t freq)21098b22851bSkettenis sxiccmu_h6_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
21108b22851bSkettenis {
211122652d99Suaa 	uint32_t parent_freq;
211222652d99Suaa 
211322652d99Suaa 	parent_freq = sxiccmu_h6_get_frequency(sc, H6_CLK_PLL_PERIPH0_2X);
211422652d99Suaa 
21158b22851bSkettenis 	switch (idx) {
21168b22851bSkettenis 	case H6_CLK_MMC0:
211722652d99Suaa 		return sxiccmu_h6_mmc_set_frequency(sc, H6_SMHC0_CLK_REG,
211822652d99Suaa 						    freq, parent_freq);
21198b22851bSkettenis 	case H6_CLK_MMC1:
212022652d99Suaa 		return sxiccmu_h6_mmc_set_frequency(sc, H6_SMHC1_CLK_REG,
212122652d99Suaa 						    freq, parent_freq);
21228b22851bSkettenis 	case H6_CLK_MMC2:
212322652d99Suaa 		return sxiccmu_h6_mmc_set_frequency(sc, H6_SMHC2_CLK_REG,
212422652d99Suaa 						    freq, parent_freq);
212522652d99Suaa 	}
212622652d99Suaa 
212722652d99Suaa 	printf("%s: 0x%08x\n", __func__, idx);
212822652d99Suaa 	return -1;
212922652d99Suaa }
213022652d99Suaa 
213122652d99Suaa #define H616_SMHC0_CLK_REG		0x0830
213222652d99Suaa #define H616_SMHC1_CLK_REG		0x0834
213322652d99Suaa #define H616_SMHC2_CLK_REG		0x0838
213422652d99Suaa 
213522652d99Suaa int
sxiccmu_h616_set_frequency(struct sxiccmu_softc * sc,uint32_t idx,uint32_t freq)213622652d99Suaa sxiccmu_h616_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
213722652d99Suaa {
213822652d99Suaa 	uint32_t parent_freq;
213922652d99Suaa 
214022652d99Suaa 	parent_freq = sxiccmu_h616_get_frequency(sc, H616_CLK_PLL_PERIPH0_2X);
214122652d99Suaa 
214222652d99Suaa 	switch (idx) {
214322652d99Suaa 	case H616_CLK_MMC0:
214422652d99Suaa 		return sxiccmu_h6_mmc_set_frequency(sc, H616_SMHC0_CLK_REG,
214522652d99Suaa 						    freq, parent_freq);
214622652d99Suaa 	case H616_CLK_MMC1:
214722652d99Suaa 		return sxiccmu_h6_mmc_set_frequency(sc, H616_SMHC1_CLK_REG,
214822652d99Suaa 						    freq, parent_freq);
214922652d99Suaa 	case H616_CLK_MMC2:
215022652d99Suaa 		return sxiccmu_h6_mmc_set_frequency(sc, H616_SMHC2_CLK_REG,
215122652d99Suaa 						    freq, parent_freq);
21528b22851bSkettenis 	}
21538b22851bSkettenis 
21548b22851bSkettenis 	printf("%s: 0x%08x\n", __func__, idx);
21558b22851bSkettenis 	return -1;
21568b22851bSkettenis }
21578b22851bSkettenis 
21582c064ff8Skettenis int
sxiccmu_r40_set_frequency(struct sxiccmu_softc * sc,uint32_t idx,uint32_t freq)2159a6d148daSkettenis sxiccmu_r40_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
2160a6d148daSkettenis {
2161a6d148daSkettenis 	struct sxiccmu_clock clock;
2162a6d148daSkettenis 	uint32_t parent, parent_freq;
2163a6d148daSkettenis 
2164a6d148daSkettenis 	switch (idx) {
2165a6d148daSkettenis 	case R40_CLK_MMC0:
2166a6d148daSkettenis 	case R40_CLK_MMC1:
2167a6d148daSkettenis 	case R40_CLK_MMC2:
2168a6d148daSkettenis 	case R40_CLK_MMC3:
2169a6d148daSkettenis 		clock.sc_iot = sc->sc_iot;
2170a6d148daSkettenis 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
2171a6d148daSkettenis 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
2172a6d148daSkettenis 		parent = R40_CLK_PLL_PERIPH0_2X;
2173a6d148daSkettenis 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
2174a6d148daSkettenis 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
2175a6d148daSkettenis 	}
2176a6d148daSkettenis 
2177a6d148daSkettenis 	printf("%s: 0x%08x\n", __func__, idx);
2178a6d148daSkettenis 	return -1;
2179a6d148daSkettenis }
2180a6d148daSkettenis 
2181a6d148daSkettenis int
sxiccmu_v3s_set_frequency(struct sxiccmu_softc * sc,uint32_t idx,uint32_t freq)21823fb3ba8fSkettenis sxiccmu_v3s_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
21833fb3ba8fSkettenis {
21843fb3ba8fSkettenis 	struct sxiccmu_clock clock;
21853fb3ba8fSkettenis 	uint32_t parent, parent_freq;
21863fb3ba8fSkettenis 
21873fb3ba8fSkettenis 	switch (idx) {
21883fb3ba8fSkettenis 	case V3S_CLK_MMC0:
21893fb3ba8fSkettenis 	case V3S_CLK_MMC1:
21903fb3ba8fSkettenis 	case V3S_CLK_MMC2:
21913fb3ba8fSkettenis 		clock.sc_iot = sc->sc_iot;
21923fb3ba8fSkettenis 		bus_space_subregion(sc->sc_iot, sc->sc_ioh,
21933fb3ba8fSkettenis 		    sc->sc_gates[idx].reg, 4, &clock.sc_ioh);
21943fb3ba8fSkettenis 		parent = V3S_CLK_PLL_PERIPH0;
21953fb3ba8fSkettenis 		parent_freq = sxiccmu_ccu_get_frequency(sc, &parent);
21963fb3ba8fSkettenis 		return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq);
21973fb3ba8fSkettenis 	}
21983fb3ba8fSkettenis 
21993fb3ba8fSkettenis 	printf("%s: 0x%08x\n", __func__, idx);
22003fb3ba8fSkettenis 	return -1;
22013fb3ba8fSkettenis }
22023fb3ba8fSkettenis 
22033fb3ba8fSkettenis int
sxiccmu_nop_set_frequency(struct sxiccmu_softc * sc,uint32_t idx,uint32_t freq)22042c064ff8Skettenis sxiccmu_nop_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
22052c064ff8Skettenis {
22062c064ff8Skettenis 	printf("%s: 0x%08x\n", __func__, idx);
22072c064ff8Skettenis 	return -1;
22082c064ff8Skettenis }
22092c064ff8Skettenis 
22100ea1c705Spatrick void
sxiccmu_ccu_enable(void * cookie,uint32_t * cells,int on)22110ea1c705Spatrick sxiccmu_ccu_enable(void *cookie, uint32_t *cells, int on)
22120ea1c705Spatrick {
22130ea1c705Spatrick 	struct sxiccmu_softc *sc = cookie;
22140ea1c705Spatrick 	uint32_t idx = cells[0];
22150ea1c705Spatrick 	int reg, bit;
22160ea1c705Spatrick 
22172c064ff8Skettenis 	clock_enable_all(sc->sc_node);
22182c064ff8Skettenis 
22192c064ff8Skettenis 	if (idx >= sc->sc_ngates ||
22202c064ff8Skettenis 	    (sc->sc_gates[idx].reg == 0 && sc->sc_gates[idx].bit == 0)) {
22210ea1c705Spatrick 		printf("%s: 0x%08x\n", __func__, cells[0]);
22220ea1c705Spatrick 		return;
22230ea1c705Spatrick 	}
22240ea1c705Spatrick 
22258b22851bSkettenis 	/* If the clock can't be gated, simply return. */
22268b22851bSkettenis 	if (sc->sc_gates[idx].reg == 0xffff && sc->sc_gates[idx].bit == 0xff)
22278b22851bSkettenis 		return;
22288b22851bSkettenis 
22290ea1c705Spatrick 	reg = sc->sc_gates[idx].reg;
22300ea1c705Spatrick 	bit = sc->sc_gates[idx].bit;
22310ea1c705Spatrick 
22320ea1c705Spatrick 	if (on)
22330ea1c705Spatrick 		SXISET4(sc, reg, (1U << bit));
22340ea1c705Spatrick 	else
22350ea1c705Spatrick 		SXICLR4(sc, reg, (1U << bit));
22360ea1c705Spatrick }
22370ea1c705Spatrick 
22380ea1c705Spatrick void
sxiccmu_ccu_reset(void * cookie,uint32_t * cells,int assert)22390ea1c705Spatrick sxiccmu_ccu_reset(void *cookie, uint32_t *cells, int assert)
22400ea1c705Spatrick {
22410ea1c705Spatrick 	struct sxiccmu_softc *sc = cookie;
22420ea1c705Spatrick 	uint32_t idx = cells[0];
22430ea1c705Spatrick 	int reg, bit;
22440ea1c705Spatrick 
22452c064ff8Skettenis 	reset_deassert_all(sc->sc_node);
22462c064ff8Skettenis 
22472c064ff8Skettenis 	if (idx >= sc->sc_nresets ||
22482c064ff8Skettenis 	    (sc->sc_resets[idx].reg == 0 && sc->sc_gates[idx].bit == 0)) {
22490ea1c705Spatrick 		printf("%s: 0x%08x\n", __func__, cells[0]);
22500ea1c705Spatrick 		return;
22510ea1c705Spatrick 	}
22520ea1c705Spatrick 
22530ea1c705Spatrick 	reg = sc->sc_resets[idx].reg;
22540ea1c705Spatrick 	bit = sc->sc_resets[idx].bit;
22550ea1c705Spatrick 
22560ea1c705Spatrick 	if (assert)
22570ea1c705Spatrick 		SXICLR4(sc, reg, (1U << bit));
22580ea1c705Spatrick 	else
22590ea1c705Spatrick 		SXISET4(sc, reg, (1U << bit));
22600ea1c705Spatrick }
2261