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