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> 416a05f063SJared McNeill #include <sys/module.h> 426a05f063SJared McNeill #include <machine/bus.h> 436a05f063SJared McNeill 446a05f063SJared McNeill #include <dev/ofw/ofw_bus.h> 456a05f063SJared McNeill #include <dev/ofw/ofw_bus_subr.h> 466a05f063SJared McNeill 476a05f063SJared McNeill #include <dev/extres/hwreset/hwreset.h> 486a05f063SJared McNeill 496a05f063SJared McNeill #include "hwreset_if.h" 506a05f063SJared McNeill 516a05f063SJared McNeill #define RESET_OFFSET(index) ((index / 32) * 4) 526a05f063SJared McNeill #define RESET_SHIFT(index) (index % 32) 536a05f063SJared McNeill 546a05f063SJared McNeill static struct ofw_compat_data compat_data[] = { 556a05f063SJared McNeill { "allwinner,sun6i-a31-ahb1-reset", 1 }, 566a05f063SJared McNeill { "allwinner,sun6i-a31-clock-reset", 1 }, 576a05f063SJared McNeill { NULL, 0 } 586a05f063SJared McNeill }; 596a05f063SJared McNeill 606a05f063SJared McNeill struct aw_reset_softc { 616a05f063SJared McNeill struct resource *res; 626a05f063SJared McNeill struct mtx mtx; 636a05f063SJared McNeill }; 646a05f063SJared McNeill 656a05f063SJared McNeill static struct resource_spec aw_reset_spec[] = { 666a05f063SJared McNeill { SYS_RES_MEMORY, 0, RF_ACTIVE }, 676a05f063SJared McNeill { -1, 0 } 686a05f063SJared McNeill }; 696a05f063SJared McNeill 706a05f063SJared McNeill #define RESET_READ(sc, reg) bus_read_4((sc)->res, (reg)) 716a05f063SJared McNeill #define RESET_WRITE(sc, reg, val) bus_write_4((sc)->res, (reg), (val)) 726a05f063SJared McNeill 736a05f063SJared McNeill static int 746a05f063SJared McNeill aw_reset_assert(device_t dev, intptr_t id, bool reset) 756a05f063SJared McNeill { 766a05f063SJared McNeill struct aw_reset_softc *sc; 776a05f063SJared McNeill uint32_t reg_value; 786a05f063SJared McNeill 796a05f063SJared McNeill sc = device_get_softc(dev); 806a05f063SJared McNeill 816a05f063SJared McNeill mtx_lock(&sc->mtx); 826a05f063SJared McNeill reg_value = RESET_READ(sc, RESET_OFFSET(id)); 836a05f063SJared McNeill if (reset) 846a05f063SJared McNeill reg_value &= ~(1 << RESET_SHIFT(id)); 856a05f063SJared McNeill else 866a05f063SJared McNeill reg_value |= (1 << RESET_SHIFT(id)); 876a05f063SJared McNeill RESET_WRITE(sc, RESET_OFFSET(id), reg_value); 886a05f063SJared McNeill mtx_unlock(&sc->mtx); 896a05f063SJared McNeill 906a05f063SJared McNeill return (0); 916a05f063SJared McNeill } 926a05f063SJared McNeill 936a05f063SJared McNeill static int 946a05f063SJared McNeill aw_reset_is_asserted(device_t dev, intptr_t id, bool *reset) 956a05f063SJared McNeill { 966a05f063SJared McNeill struct aw_reset_softc *sc; 976a05f063SJared McNeill uint32_t reg_value; 986a05f063SJared McNeill 996a05f063SJared McNeill sc = device_get_softc(dev); 1006a05f063SJared McNeill 1016a05f063SJared McNeill mtx_lock(&sc->mtx); 1026a05f063SJared McNeill reg_value = RESET_READ(sc, RESET_OFFSET(id)); 1036a05f063SJared McNeill mtx_unlock(&sc->mtx); 1046a05f063SJared McNeill 1056a05f063SJared McNeill *reset = (reg_value & (1 << RESET_SHIFT(id))) != 0 ? false : true; 1066a05f063SJared McNeill 1076a05f063SJared McNeill return (0); 1086a05f063SJared McNeill } 1096a05f063SJared McNeill 1106a05f063SJared McNeill static int 1116a05f063SJared McNeill aw_reset_probe(device_t dev) 1126a05f063SJared McNeill { 1136a05f063SJared McNeill if (!ofw_bus_status_okay(dev)) 1146a05f063SJared McNeill return (ENXIO); 1156a05f063SJared McNeill 1166a05f063SJared McNeill if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 1176a05f063SJared McNeill return (ENXIO); 1186a05f063SJared McNeill 1196a05f063SJared McNeill device_set_desc(dev, "Allwinner Module Resets"); 1206a05f063SJared McNeill return (BUS_PROBE_DEFAULT); 1216a05f063SJared McNeill } 1226a05f063SJared McNeill 1236a05f063SJared McNeill static int 1246a05f063SJared McNeill aw_reset_attach(device_t dev) 1256a05f063SJared McNeill { 1266a05f063SJared McNeill struct aw_reset_softc *sc; 1276a05f063SJared McNeill 1286a05f063SJared McNeill sc = device_get_softc(dev); 1296a05f063SJared McNeill 1306a05f063SJared McNeill if (bus_alloc_resources(dev, aw_reset_spec, &sc->res) != 0) { 1316a05f063SJared McNeill device_printf(dev, "cannot allocate resources for device\n"); 1326a05f063SJared McNeill return (ENXIO); 1336a05f063SJared McNeill } 1346a05f063SJared McNeill 1356a05f063SJared McNeill mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF); 1366a05f063SJared McNeill 1376a05f063SJared McNeill hwreset_register_ofw_provider(dev); 1386a05f063SJared McNeill 1396a05f063SJared McNeill return (0); 1406a05f063SJared McNeill } 1416a05f063SJared McNeill 1426a05f063SJared McNeill static device_method_t aw_reset_methods[] = { 1436a05f063SJared McNeill /* Device interface */ 1446a05f063SJared McNeill DEVMETHOD(device_probe, aw_reset_probe), 1456a05f063SJared McNeill DEVMETHOD(device_attach, aw_reset_attach), 1466a05f063SJared McNeill 1476a05f063SJared McNeill /* Reset interface */ 1486a05f063SJared McNeill DEVMETHOD(hwreset_assert, aw_reset_assert), 1496a05f063SJared McNeill DEVMETHOD(hwreset_is_asserted, aw_reset_is_asserted), 1506a05f063SJared McNeill 1516a05f063SJared McNeill DEVMETHOD_END 1526a05f063SJared McNeill }; 1536a05f063SJared McNeill 1546a05f063SJared McNeill static driver_t aw_reset_driver = { 1556a05f063SJared McNeill "aw_reset", 1566a05f063SJared McNeill aw_reset_methods, 1576a05f063SJared McNeill sizeof(struct aw_reset_softc), 1586a05f063SJared McNeill }; 1596a05f063SJared McNeill 1606a05f063SJared McNeill static devclass_t aw_reset_devclass; 1616a05f063SJared McNeill 162*65d6a5a4SJared McNeill EARLY_DRIVER_MODULE(aw_reset, simplebus, aw_reset_driver, aw_reset_devclass, 163*65d6a5a4SJared McNeill 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); 1646a05f063SJared McNeill MODULE_VERSION(aw_reset, 1); 165