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