xref: /netbsd-src/sys/arch/arm/sunxi/sunxi_resets.c (revision 6e54367a22fbc89a1139d033e95bec0c0cf0975b)
1*6e54367aSthorpej /* $NetBSD: sunxi_resets.c,v 1.2 2021/01/27 03:10:20 thorpej Exp $ */
27283846bSjmcneill 
37283846bSjmcneill /*-
47283846bSjmcneill  * Copyright (c) 2017 Jared McNeill <jmcneill@invisible.ca>
57283846bSjmcneill  * All rights reserved.
67283846bSjmcneill  *
77283846bSjmcneill  * Redistribution and use in source and binary forms, with or without
87283846bSjmcneill  * modification, are permitted provided that the following conditions
97283846bSjmcneill  * are met:
107283846bSjmcneill  * 1. Redistributions of source code must retain the above copyright
117283846bSjmcneill  *    notice, this list of conditions and the following disclaimer.
127283846bSjmcneill  * 2. Redistributions in binary form must reproduce the above copyright
137283846bSjmcneill  *    notice, this list of conditions and the following disclaimer in the
147283846bSjmcneill  *    documentation and/or other materials provided with the distribution.
157283846bSjmcneill  *
167283846bSjmcneill  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
177283846bSjmcneill  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
187283846bSjmcneill  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
197283846bSjmcneill  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
207283846bSjmcneill  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
217283846bSjmcneill  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
227283846bSjmcneill  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
237283846bSjmcneill  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
247283846bSjmcneill  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
257283846bSjmcneill  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
267283846bSjmcneill  * SUCH DAMAGE.
277283846bSjmcneill  */
287283846bSjmcneill 
297283846bSjmcneill #include <sys/cdefs.h>
30*6e54367aSthorpej __KERNEL_RCSID(0, "$NetBSD: sunxi_resets.c,v 1.2 2021/01/27 03:10:20 thorpej Exp $");
317283846bSjmcneill 
327283846bSjmcneill #include <sys/param.h>
337283846bSjmcneill #include <sys/bus.h>
347283846bSjmcneill #include <sys/cpu.h>
357283846bSjmcneill #include <sys/device.h>
367283846bSjmcneill 
377283846bSjmcneill #include <dev/fdt/fdtvar.h>
387283846bSjmcneill 
397283846bSjmcneill #include <dev/clk/clk_backend.h>
407283846bSjmcneill 
417283846bSjmcneill #define	RESET_REG(index)	(((index) / 32) * 4)
427283846bSjmcneill #define	RESET_MASK(index)	__BIT((index) % 32)
437283846bSjmcneill 
44*6e54367aSthorpej static const struct device_compatible_entry compat_data[] = {
45*6e54367aSthorpej 	{ .compat = "allwinner,sun6i-a31-clock-reset" },
46*6e54367aSthorpej 	DEVICE_COMPAT_EOL
477283846bSjmcneill };
487283846bSjmcneill 
497283846bSjmcneill struct sunxi_resets_softc {
507283846bSjmcneill 	device_t		sc_dev;
517283846bSjmcneill 	bus_space_tag_t		sc_bst;
527283846bSjmcneill 	bus_space_handle_t	sc_bsh;
537283846bSjmcneill };
547283846bSjmcneill 
557283846bSjmcneill #define	RESET_READ(sc, reg)		\
567283846bSjmcneill 	bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
577283846bSjmcneill #define	RESET_WRITE(sc, reg, val)	\
587283846bSjmcneill 	bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
597283846bSjmcneill 
607283846bSjmcneill static void *
sunxi_resets_acquire(device_t dev,const void * data,size_t len)617283846bSjmcneill sunxi_resets_acquire(device_t dev, const void *data, size_t len)
627283846bSjmcneill {
637283846bSjmcneill 	if (len != 4)
647283846bSjmcneill 		return NULL;
657283846bSjmcneill 
667283846bSjmcneill 	/* Specifier is an index. Just return it. */
677283846bSjmcneill 	return (void *)(uintptr_t)be32dec(data);
687283846bSjmcneill }
697283846bSjmcneill 
707283846bSjmcneill static void
sunxi_resets_release(device_t dev,void * priv)717283846bSjmcneill sunxi_resets_release(device_t dev, void *priv)
727283846bSjmcneill {
737283846bSjmcneill }
747283846bSjmcneill 
757283846bSjmcneill static int
sunxi_resets_assert(device_t dev,void * priv)767283846bSjmcneill sunxi_resets_assert(device_t dev, void *priv)
777283846bSjmcneill {
787283846bSjmcneill 	struct sunxi_resets_softc * const sc = device_private(dev);
797283846bSjmcneill 	const uintptr_t index = (uintptr_t)priv;
807283846bSjmcneill 
817283846bSjmcneill 	const bus_size_t reset_reg = RESET_REG(index);
827283846bSjmcneill 	const uint32_t reset_mask = RESET_MASK(index);
837283846bSjmcneill 
847283846bSjmcneill 	const uint32_t val = RESET_READ(sc, reset_reg);
857283846bSjmcneill 	RESET_WRITE(sc, reset_reg, val & ~reset_mask);
867283846bSjmcneill 
877283846bSjmcneill 	return 0;
887283846bSjmcneill }
897283846bSjmcneill 
907283846bSjmcneill static int
sunxi_resets_deassert(device_t dev,void * priv)917283846bSjmcneill sunxi_resets_deassert(device_t dev, void *priv)
927283846bSjmcneill {
937283846bSjmcneill 	struct sunxi_resets_softc * const sc = device_private(dev);
947283846bSjmcneill 	const uintptr_t index = (uintptr_t)priv;
957283846bSjmcneill 
967283846bSjmcneill 	const bus_size_t reset_reg = RESET_REG(index);
977283846bSjmcneill 	const uint32_t reset_mask = RESET_MASK(index);
987283846bSjmcneill 
997283846bSjmcneill 	const uint32_t val = RESET_READ(sc, reset_reg);
1007283846bSjmcneill 	RESET_WRITE(sc, reset_reg, val | reset_mask);
1017283846bSjmcneill 
1027283846bSjmcneill 	return 0;
1037283846bSjmcneill }
1047283846bSjmcneill 
1057283846bSjmcneill static const struct fdtbus_reset_controller_func sunxi_fdtreset_funcs = {
1067283846bSjmcneill 	.acquire = sunxi_resets_acquire,
1077283846bSjmcneill 	.release = sunxi_resets_release,
1087283846bSjmcneill 	.reset_assert = sunxi_resets_assert,
1097283846bSjmcneill 	.reset_deassert = sunxi_resets_deassert,
1107283846bSjmcneill };
1117283846bSjmcneill 
1127283846bSjmcneill static int
sunxi_resets_match(device_t parent,cfdata_t cf,void * aux)1137283846bSjmcneill sunxi_resets_match(device_t parent, cfdata_t cf, void *aux)
1147283846bSjmcneill {
1157283846bSjmcneill 	struct fdt_attach_args * const faa = aux;
1167283846bSjmcneill 
117*6e54367aSthorpej 	return of_compatible_match(faa->faa_phandle, compat_data);
1187283846bSjmcneill }
1197283846bSjmcneill 
1207283846bSjmcneill static void
sunxi_resets_attach(device_t parent,device_t self,void * aux)1217283846bSjmcneill sunxi_resets_attach(device_t parent, device_t self, void *aux)
1227283846bSjmcneill {
1237283846bSjmcneill 	struct sunxi_resets_softc * const sc = device_private(self);
1247283846bSjmcneill 	struct fdt_attach_args * const faa = aux;
1257283846bSjmcneill 	const int phandle = faa->faa_phandle;
1267283846bSjmcneill 	bus_addr_t addr;
1277283846bSjmcneill 	bus_size_t size;
1287283846bSjmcneill 
1297283846bSjmcneill 	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
1307283846bSjmcneill 		aprint_error(": couldn't get registers\n");
1317283846bSjmcneill 		return;
1327283846bSjmcneill 	}
1337283846bSjmcneill 
1347283846bSjmcneill 	sc->sc_dev = self;
1357283846bSjmcneill 	sc->sc_bst = faa->faa_bst;
1367283846bSjmcneill 	if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
1377283846bSjmcneill 		aprint_error(": couldn't map registers\n");
1387283846bSjmcneill 		return;
1397283846bSjmcneill 	}
1407283846bSjmcneill 
1417283846bSjmcneill 	aprint_naive("\n");
1427283846bSjmcneill 	aprint_normal("\n");
1437283846bSjmcneill 
1447283846bSjmcneill 	fdtbus_register_reset_controller(sc->sc_dev, phandle,
1457283846bSjmcneill 	    &sunxi_fdtreset_funcs);
1467283846bSjmcneill }
1477283846bSjmcneill 
1487283846bSjmcneill CFATTACH_DECL_NEW(sunxi_resets, sizeof(struct sunxi_resets_softc),
1497283846bSjmcneill     sunxi_resets_match, sunxi_resets_attach, NULL, NULL);
150