16a05f063SJared McNeill /*- 26a05f063SJared McNeill * Copyright (c) 2016 Jared McNeill <jmcneill@invisible.ca> 36a05f063SJared McNeill * All rights reserved. 46a05f063SJared McNeill * 56a05f063SJared McNeill * Redistribution and use in source and binary forms, with or without 66a05f063SJared McNeill * modification, are permitted provided that the following conditions 76a05f063SJared McNeill * are met: 86a05f063SJared McNeill * 1. Redistributions of source code must retain the above copyright 96a05f063SJared McNeill * notice, this list of conditions and the following disclaimer. 106a05f063SJared McNeill * 2. Redistributions in binary form must reproduce the above copyright 116a05f063SJared McNeill * notice, this list of conditions and the following disclaimer in the 126a05f063SJared McNeill * documentation and/or other materials provided with the distribution. 136a05f063SJared McNeill * 146a05f063SJared McNeill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 156a05f063SJared McNeill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 166a05f063SJared McNeill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 176a05f063SJared McNeill * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 186a05f063SJared McNeill * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 196a05f063SJared McNeill * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 206a05f063SJared McNeill * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 216a05f063SJared McNeill * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 226a05f063SJared McNeill * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 236a05f063SJared McNeill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 246a05f063SJared McNeill * SUCH DAMAGE. 256a05f063SJared McNeill * 266a05f063SJared McNeill * $FreeBSD$ 276a05f063SJared McNeill */ 286a05f063SJared McNeill 296a05f063SJared McNeill /* 306a05f063SJared McNeill * Allwinner module software reset registers 316a05f063SJared McNeill */ 326a05f063SJared McNeill 336a05f063SJared McNeill #include <sys/cdefs.h> 346a05f063SJared McNeill __FBSDID("$FreeBSD$"); 356a05f063SJared McNeill 366a05f063SJared McNeill #include <sys/param.h> 376a05f063SJared McNeill #include <sys/systm.h> 386a05f063SJared McNeill #include <sys/bus.h> 396a05f063SJared McNeill #include <sys/rman.h> 406a05f063SJared McNeill #include <sys/kernel.h> 41*e2e050c8SConrad Meyer #include <sys/lock.h> 426a05f063SJared McNeill #include <sys/module.h> 43*e2e050c8SConrad Meyer #include <sys/mutex.h> 446a05f063SJared McNeill #include <machine/bus.h> 456a05f063SJared McNeill 466a05f063SJared McNeill #include <dev/ofw/ofw_bus.h> 476a05f063SJared McNeill #include <dev/ofw/ofw_bus_subr.h> 486a05f063SJared McNeill 496a05f063SJared McNeill #include <dev/extres/hwreset/hwreset.h> 506a05f063SJared McNeill 516a05f063SJared McNeill #include "hwreset_if.h" 526a05f063SJared McNeill 536a05f063SJared McNeill #define RESET_OFFSET(index) ((index / 32) * 4) 546a05f063SJared McNeill #define RESET_SHIFT(index) (index % 32) 556a05f063SJared McNeill 566a05f063SJared McNeill static struct ofw_compat_data compat_data[] = { 576a05f063SJared McNeill { "allwinner,sun6i-a31-ahb1-reset", 1 }, 586a05f063SJared McNeill { "allwinner,sun6i-a31-clock-reset", 1 }, 596a05f063SJared McNeill { NULL, 0 } 606a05f063SJared McNeill }; 616a05f063SJared McNeill 626a05f063SJared McNeill struct aw_reset_softc { 636a05f063SJared McNeill struct resource *res; 646a05f063SJared McNeill struct mtx mtx; 656a05f063SJared McNeill }; 666a05f063SJared McNeill 676a05f063SJared McNeill static struct resource_spec aw_reset_spec[] = { 686a05f063SJared McNeill { SYS_RES_MEMORY, 0, RF_ACTIVE }, 696a05f063SJared McNeill { -1, 0 } 706a05f063SJared McNeill }; 716a05f063SJared McNeill 726a05f063SJared McNeill #define RESET_READ(sc, reg) bus_read_4((sc)->res, (reg)) 736a05f063SJared McNeill #define RESET_WRITE(sc, reg, val) bus_write_4((sc)->res, (reg), (val)) 746a05f063SJared McNeill 756a05f063SJared McNeill static int 766a05f063SJared McNeill aw_reset_assert(device_t dev, intptr_t id, bool reset) 776a05f063SJared McNeill { 786a05f063SJared McNeill struct aw_reset_softc *sc; 796a05f063SJared McNeill uint32_t reg_value; 806a05f063SJared McNeill 816a05f063SJared McNeill sc = device_get_softc(dev); 826a05f063SJared McNeill 836a05f063SJared McNeill mtx_lock(&sc->mtx); 846a05f063SJared McNeill reg_value = RESET_READ(sc, RESET_OFFSET(id)); 856a05f063SJared McNeill if (reset) 866a05f063SJared McNeill reg_value &= ~(1 << RESET_SHIFT(id)); 876a05f063SJared McNeill else 886a05f063SJared McNeill reg_value |= (1 << RESET_SHIFT(id)); 896a05f063SJared McNeill RESET_WRITE(sc, RESET_OFFSET(id), reg_value); 906a05f063SJared McNeill mtx_unlock(&sc->mtx); 916a05f063SJared McNeill 926a05f063SJared McNeill return (0); 936a05f063SJared McNeill } 946a05f063SJared McNeill 956a05f063SJared McNeill static int 966a05f063SJared McNeill aw_reset_is_asserted(device_t dev, intptr_t id, bool *reset) 976a05f063SJared McNeill { 986a05f063SJared McNeill struct aw_reset_softc *sc; 996a05f063SJared McNeill uint32_t reg_value; 1006a05f063SJared McNeill 1016a05f063SJared McNeill sc = device_get_softc(dev); 1026a05f063SJared McNeill 1036a05f063SJared McNeill mtx_lock(&sc->mtx); 1046a05f063SJared McNeill reg_value = RESET_READ(sc, RESET_OFFSET(id)); 1056a05f063SJared McNeill mtx_unlock(&sc->mtx); 1066a05f063SJared McNeill 1076a05f063SJared McNeill *reset = (reg_value & (1 << RESET_SHIFT(id))) != 0 ? false : true; 1086a05f063SJared McNeill 1096a05f063SJared McNeill return (0); 1106a05f063SJared McNeill } 1116a05f063SJared McNeill 1126a05f063SJared McNeill static int 1136a05f063SJared McNeill aw_reset_probe(device_t dev) 1146a05f063SJared McNeill { 1156a05f063SJared McNeill if (!ofw_bus_status_okay(dev)) 1166a05f063SJared McNeill return (ENXIO); 1176a05f063SJared McNeill 1186a05f063SJared McNeill if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 1196a05f063SJared McNeill return (ENXIO); 1206a05f063SJared McNeill 1216a05f063SJared McNeill device_set_desc(dev, "Allwinner Module Resets"); 1226a05f063SJared McNeill return (BUS_PROBE_DEFAULT); 1236a05f063SJared McNeill } 1246a05f063SJared McNeill 1256a05f063SJared McNeill static int 1266a05f063SJared McNeill aw_reset_attach(device_t dev) 1276a05f063SJared McNeill { 1286a05f063SJared McNeill struct aw_reset_softc *sc; 1296a05f063SJared McNeill 1306a05f063SJared McNeill sc = device_get_softc(dev); 1316a05f063SJared McNeill 1326a05f063SJared McNeill if (bus_alloc_resources(dev, aw_reset_spec, &sc->res) != 0) { 1336a05f063SJared McNeill device_printf(dev, "cannot allocate resources for device\n"); 1346a05f063SJared McNeill return (ENXIO); 1356a05f063SJared McNeill } 1366a05f063SJared McNeill 1376a05f063SJared McNeill mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF); 1386a05f063SJared McNeill 1396a05f063SJared McNeill hwreset_register_ofw_provider(dev); 1406a05f063SJared McNeill 1416a05f063SJared McNeill return (0); 1426a05f063SJared McNeill } 1436a05f063SJared McNeill 1446a05f063SJared McNeill static device_method_t aw_reset_methods[] = { 1456a05f063SJared McNeill /* Device interface */ 1466a05f063SJared McNeill DEVMETHOD(device_probe, aw_reset_probe), 1476a05f063SJared McNeill DEVMETHOD(device_attach, aw_reset_attach), 1486a05f063SJared McNeill 1496a05f063SJared McNeill /* Reset interface */ 1506a05f063SJared McNeill DEVMETHOD(hwreset_assert, aw_reset_assert), 1516a05f063SJared McNeill DEVMETHOD(hwreset_is_asserted, aw_reset_is_asserted), 1526a05f063SJared McNeill 1536a05f063SJared McNeill DEVMETHOD_END 1546a05f063SJared McNeill }; 1556a05f063SJared McNeill 1566a05f063SJared McNeill static driver_t aw_reset_driver = { 1576a05f063SJared McNeill "aw_reset", 1586a05f063SJared McNeill aw_reset_methods, 1596a05f063SJared McNeill sizeof(struct aw_reset_softc), 1606a05f063SJared McNeill }; 1616a05f063SJared McNeill 1626a05f063SJared McNeill static devclass_t aw_reset_devclass; 1636a05f063SJared McNeill 16465d6a5a4SJared McNeill EARLY_DRIVER_MODULE(aw_reset, simplebus, aw_reset_driver, aw_reset_devclass, 16565d6a5a4SJared McNeill 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); 1666a05f063SJared McNeill MODULE_VERSION(aw_reset, 1); 167