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