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