xref: /openbsd-src/sys/arch/arm64/dev/aplsart.c (revision ea87a8bf468d59502d176fee1979ff5c974b6942)
1*ea87a8bfSkettenis /*	$OpenBSD: aplsart.c,v 1.4 2022/11/11 11:45:10 kettenis Exp $	*/
22ec5c635Skettenis /*
32ec5c635Skettenis  * Copyright (c) 2022 Mark Kettenis <kettenis@openbsd.org>
42ec5c635Skettenis  *
52ec5c635Skettenis  * Permission to use, copy, modify, and distribute this software for any
62ec5c635Skettenis  * purpose with or without fee is hereby granted, provided that the above
72ec5c635Skettenis  * copyright notice and this permission notice appear in all copies.
82ec5c635Skettenis  *
92ec5c635Skettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
102ec5c635Skettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
112ec5c635Skettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
122ec5c635Skettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
132ec5c635Skettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
142ec5c635Skettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
152ec5c635Skettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
162ec5c635Skettenis  */
172ec5c635Skettenis 
182ec5c635Skettenis #include <sys/param.h>
192ec5c635Skettenis #include <sys/systm.h>
202ec5c635Skettenis #include <sys/device.h>
212ec5c635Skettenis #include <sys/extent.h>
222ec5c635Skettenis #include <sys/malloc.h>
232ec5c635Skettenis #include <sys/mutex.h>
242ec5c635Skettenis 
252ec5c635Skettenis #include <machine/intr.h>
262ec5c635Skettenis #include <machine/bus.h>
272ec5c635Skettenis #include <machine/fdt.h>
282ec5c635Skettenis 
292ec5c635Skettenis #include <dev/ofw/openfirm.h>
302ec5c635Skettenis #include <dev/ofw/fdt.h>
31e744461dSkettenis #include <dev/ofw/ofw_power.h>
322ec5c635Skettenis 
332ec5c635Skettenis #define SART2_CONFIG(idx)	(0x0000 + 4 * (idx))
342ec5c635Skettenis #define  SART2_CONFIG_FLAGS_MASK	0xff000000
352ec5c635Skettenis #define  SART2_CONFIG_FLAGS_ALLOW	0xff000000
362ec5c635Skettenis #define SART2_ADDR(idx)		(0x0040 + 4 * (idx))
372ec5c635Skettenis 
382ec5c635Skettenis #define SART3_CONFIG(idx)	(0x0000 + 4 * (idx))
392ec5c635Skettenis #define  SART3_CONFIG_FLAGS_MASK	0x000000ff
402ec5c635Skettenis #define  SART3_CONFIG_FLAGS_ALLOW	0x000000ff
412ec5c635Skettenis #define SART3_ADDR(idx)		(0x0040 + 4 * (idx))
422ec5c635Skettenis #define SART3_SIZE(idx)		(0x0080 + 4 * (idx))
432ec5c635Skettenis 
442ec5c635Skettenis #define SART_NUM_ENTRIES	16
452ec5c635Skettenis #define SART_ADDR_SHIFT		12
462ec5c635Skettenis #define SART_SIZE_SHIFT		12
472ec5c635Skettenis 
482ec5c635Skettenis #define HREAD4(sc, reg)							\
492ec5c635Skettenis 	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
502ec5c635Skettenis #define HWRITE4(sc, reg, val)						\
512ec5c635Skettenis 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
522ec5c635Skettenis 
532ec5c635Skettenis struct aplsart_softc {
542ec5c635Skettenis 	struct device		sc_dev;
552ec5c635Skettenis 	bus_space_tag_t		sc_iot;
562ec5c635Skettenis 	bus_space_handle_t	sc_ioh;
57e744461dSkettenis 	int			sc_node;
582ec5c635Skettenis 	uint32_t		sc_phandle;
592ec5c635Skettenis 	int			sc_version;
602ec5c635Skettenis };
612ec5c635Skettenis 
622ec5c635Skettenis int	aplsart_match(struct device *, void *, void *);
632ec5c635Skettenis void	aplsart_attach(struct device *, struct device *, void *);
64e744461dSkettenis int	aplsart_activate(struct device *, int);
652ec5c635Skettenis 
662ec5c635Skettenis const struct cfattach aplsart_ca = {
67e744461dSkettenis 	sizeof (struct aplsart_softc), aplsart_match, aplsart_attach, NULL,
68e744461dSkettenis 	aplsart_activate
692ec5c635Skettenis };
702ec5c635Skettenis 
712ec5c635Skettenis struct cfdriver aplsart_cd = {
722ec5c635Skettenis 	NULL, "aplsart", DV_DULL
732ec5c635Skettenis };
742ec5c635Skettenis 
752ec5c635Skettenis int
aplsart_match(struct device * parent,void * match,void * aux)762ec5c635Skettenis aplsart_match(struct device *parent, void *match, void *aux)
772ec5c635Skettenis {
782ec5c635Skettenis 	struct fdt_attach_args *faa = aux;
792ec5c635Skettenis 
801d0ffe23Skettenis 	return OF_is_compatible(faa->fa_node, "apple,t6000-sart") ||
811d0ffe23Skettenis 	    OF_is_compatible(faa->fa_node, "apple,t8103-sart");
822ec5c635Skettenis }
832ec5c635Skettenis 
842ec5c635Skettenis void
aplsart_attach(struct device * parent,struct device * self,void * aux)852ec5c635Skettenis aplsart_attach(struct device *parent, struct device *self, void *aux)
862ec5c635Skettenis {
872ec5c635Skettenis 	struct aplsart_softc *sc = (struct aplsart_softc *)self;
882ec5c635Skettenis 	struct fdt_attach_args *faa = aux;
892ec5c635Skettenis 
902ec5c635Skettenis 	if (faa->fa_nreg < 1) {
912ec5c635Skettenis 		printf(": no registers\n");
922ec5c635Skettenis 		return;
932ec5c635Skettenis 	}
942ec5c635Skettenis 
952ec5c635Skettenis 	sc->sc_iot = faa->fa_iot;
962ec5c635Skettenis 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
972ec5c635Skettenis 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
982ec5c635Skettenis 		printf(": can't map registers\n");
992ec5c635Skettenis 		return;
1002ec5c635Skettenis 	}
1012ec5c635Skettenis 
102e744461dSkettenis 	sc->sc_node = faa->fa_node;
1032ec5c635Skettenis 	sc->sc_phandle = OF_getpropint(faa->fa_node, "phandle", 0);
1042ec5c635Skettenis 
105e744461dSkettenis 	if (OF_is_compatible(sc->sc_node, "apple,t8103-sart"))
1062ec5c635Skettenis 		sc->sc_version = 2;
107e744461dSkettenis 	if (OF_is_compatible(sc->sc_node, "apple,t6000-sart"))
1082ec5c635Skettenis 		sc->sc_version = 3;
1092ec5c635Skettenis 
110e744461dSkettenis 	power_domain_enable_all(sc->sc_node);
111e744461dSkettenis 
1122ec5c635Skettenis 	printf("\n");
1132ec5c635Skettenis }
1142ec5c635Skettenis 
1152ec5c635Skettenis int
aplsart_activate(struct device * self,int act)116e744461dSkettenis aplsart_activate(struct device *self, int act)
117e744461dSkettenis {
118e744461dSkettenis 	struct aplsart_softc *sc = (struct aplsart_softc *)self;
119e744461dSkettenis 
120e744461dSkettenis 	switch (act) {
121e744461dSkettenis 	case DVACT_POWERDOWN:
122e744461dSkettenis 		power_domain_disable_all(sc->sc_node);
123e744461dSkettenis 		break;
124e744461dSkettenis 	case DVACT_RESUME:
125e744461dSkettenis 		power_domain_enable_all(sc->sc_node);
126e744461dSkettenis 		break;
127e744461dSkettenis 	}
128e744461dSkettenis 
129e744461dSkettenis 	return 0;
130e744461dSkettenis }
131e744461dSkettenis 
132e744461dSkettenis int
aplsart2_map(struct aplsart_softc * sc,bus_addr_t addr,bus_size_t size)1332ec5c635Skettenis aplsart2_map(struct aplsart_softc *sc, bus_addr_t addr, bus_size_t size)
1342ec5c635Skettenis {
1352ec5c635Skettenis 	uint32_t conf;
1362ec5c635Skettenis 	int i;
1372ec5c635Skettenis 
1382ec5c635Skettenis 	for (i = 0; i < SART_NUM_ENTRIES; i++) {
1392ec5c635Skettenis 		conf = HREAD4(sc, SART2_CONFIG(i));
1402ec5c635Skettenis 		if (conf & SART2_CONFIG_FLAGS_MASK)
1412ec5c635Skettenis 			continue;
1422ec5c635Skettenis 
1432ec5c635Skettenis 		HWRITE4(sc, SART2_ADDR(i), addr >> SART_ADDR_SHIFT);
1442ec5c635Skettenis 		HWRITE4(sc, SART2_CONFIG(i),
1452ec5c635Skettenis 		    size >> SART_SIZE_SHIFT | SART2_CONFIG_FLAGS_ALLOW);
1462ec5c635Skettenis 		return 0;
1472ec5c635Skettenis 	}
1482ec5c635Skettenis 
1492ec5c635Skettenis 	return ENOENT;
1502ec5c635Skettenis }
1512ec5c635Skettenis 
1522ec5c635Skettenis int
aplsart3_map(struct aplsart_softc * sc,bus_addr_t addr,bus_size_t size)1532ec5c635Skettenis aplsart3_map(struct aplsart_softc *sc, bus_addr_t addr, bus_size_t size)
1542ec5c635Skettenis {
1552ec5c635Skettenis 	uint32_t conf;
1562ec5c635Skettenis 	int i;
1572ec5c635Skettenis 
1582ec5c635Skettenis 	for (i = 0; i < SART_NUM_ENTRIES; i++) {
1592ec5c635Skettenis 		conf = HREAD4(sc, SART3_CONFIG(i));
1602ec5c635Skettenis 		if (conf & SART3_CONFIG_FLAGS_MASK)
1612ec5c635Skettenis 			continue;
1622ec5c635Skettenis 
1632ec5c635Skettenis 		HWRITE4(sc, SART3_ADDR(i), addr >> SART_ADDR_SHIFT);
1642ec5c635Skettenis 		HWRITE4(sc, SART3_SIZE(i), size >> SART_SIZE_SHIFT);
1652ec5c635Skettenis 		HWRITE4(sc, SART3_CONFIG(i), SART3_CONFIG_FLAGS_ALLOW);
1662ec5c635Skettenis 		return 0;
1672ec5c635Skettenis 	}
1682ec5c635Skettenis 
1692ec5c635Skettenis 	return ENOENT;
1702ec5c635Skettenis }
1712ec5c635Skettenis 
1722ec5c635Skettenis int
aplsart_map(uint32_t phandle,bus_addr_t addr,bus_size_t size)1732ec5c635Skettenis aplsart_map(uint32_t phandle, bus_addr_t addr, bus_size_t size)
1742ec5c635Skettenis {
1752ec5c635Skettenis 	struct aplsart_softc *sc;
1762ec5c635Skettenis 	int i;
1772ec5c635Skettenis 
1782ec5c635Skettenis 	for (i = 0; i < aplsart_cd.cd_ndevs; i++) {
1792ec5c635Skettenis 		sc = (struct aplsart_softc *)aplsart_cd.cd_devs[i];
1802ec5c635Skettenis 
1812ec5c635Skettenis 		if (sc->sc_phandle == phandle) {
1822ec5c635Skettenis 			if (sc->sc_version == 2)
1832ec5c635Skettenis 				return aplsart2_map(sc, addr, size);
1842ec5c635Skettenis 			else
1852ec5c635Skettenis 				return aplsart3_map(sc, addr, size);
1862ec5c635Skettenis 		}
1872ec5c635Skettenis 	}
1882ec5c635Skettenis 
1892ec5c635Skettenis 	return ENXIO;
1902ec5c635Skettenis }
191*ea87a8bfSkettenis 
192*ea87a8bfSkettenis int
aplsart2_unmap(struct aplsart_softc * sc,bus_addr_t addr,bus_size_t size)193*ea87a8bfSkettenis aplsart2_unmap(struct aplsart_softc *sc, bus_addr_t addr, bus_size_t size)
194*ea87a8bfSkettenis {
195*ea87a8bfSkettenis 	int i;
196*ea87a8bfSkettenis 
197*ea87a8bfSkettenis 	for (i = 0; i < SART_NUM_ENTRIES; i++) {
198*ea87a8bfSkettenis 		if (HREAD4(sc, SART2_ADDR(i)) != (addr >> SART_ADDR_SHIFT))
199*ea87a8bfSkettenis 			continue;
200*ea87a8bfSkettenis 
201*ea87a8bfSkettenis 		HWRITE4(sc, SART2_ADDR(i), 0);
202*ea87a8bfSkettenis 		HWRITE4(sc, SART2_CONFIG(i), 0);
203*ea87a8bfSkettenis 		return 0;
204*ea87a8bfSkettenis 	}
205*ea87a8bfSkettenis 
206*ea87a8bfSkettenis 	return ENOENT;
207*ea87a8bfSkettenis }
208*ea87a8bfSkettenis 
209*ea87a8bfSkettenis int
aplsart3_unmap(struct aplsart_softc * sc,bus_addr_t addr,bus_size_t size)210*ea87a8bfSkettenis aplsart3_unmap(struct aplsart_softc *sc, bus_addr_t addr, bus_size_t size)
211*ea87a8bfSkettenis {
212*ea87a8bfSkettenis 	int i;
213*ea87a8bfSkettenis 
214*ea87a8bfSkettenis 	for (i = 0; i < SART_NUM_ENTRIES; i++) {
215*ea87a8bfSkettenis 		if (HREAD4(sc, SART3_ADDR(i)) != (addr >> SART_ADDR_SHIFT))
216*ea87a8bfSkettenis 			continue;
217*ea87a8bfSkettenis 
218*ea87a8bfSkettenis 		HWRITE4(sc, SART3_ADDR(i), 0);
219*ea87a8bfSkettenis 		HWRITE4(sc, SART3_SIZE(i), 0);
220*ea87a8bfSkettenis 		HWRITE4(sc, SART3_CONFIG(i), 0);
221*ea87a8bfSkettenis 		return 0;
222*ea87a8bfSkettenis 	}
223*ea87a8bfSkettenis 
224*ea87a8bfSkettenis 	return ENOENT;
225*ea87a8bfSkettenis }
226*ea87a8bfSkettenis 
227*ea87a8bfSkettenis int
aplsart_unmap(uint32_t phandle,bus_addr_t addr,bus_size_t size)228*ea87a8bfSkettenis aplsart_unmap(uint32_t phandle, bus_addr_t addr, bus_size_t size)
229*ea87a8bfSkettenis {
230*ea87a8bfSkettenis 	struct aplsart_softc *sc;
231*ea87a8bfSkettenis 	int i;
232*ea87a8bfSkettenis 
233*ea87a8bfSkettenis 	for (i = 0; i < aplsart_cd.cd_ndevs; i++) {
234*ea87a8bfSkettenis 		sc = (struct aplsart_softc *)aplsart_cd.cd_devs[i];
235*ea87a8bfSkettenis 
236*ea87a8bfSkettenis 		if (sc->sc_phandle == phandle) {
237*ea87a8bfSkettenis 			if (sc->sc_version == 2)
238*ea87a8bfSkettenis 				return aplsart2_unmap(sc, addr, size);
239*ea87a8bfSkettenis 			else
240*ea87a8bfSkettenis 				return aplsart3_unmap(sc, addr, size);
241*ea87a8bfSkettenis 		}
242*ea87a8bfSkettenis 	}
243*ea87a8bfSkettenis 
244*ea87a8bfSkettenis 	return ENXIO;
245*ea87a8bfSkettenis }
246