xref: /freebsd/sys/arm/allwinner/aw_reset.c (revision e2e050c8ef733138fc6a9e514e4b856fefbc3ff1)
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