xref: /openbsd-src/sys/arch/arm64/dev/aplmbox.c (revision 7ab4cc9835a16d0789381992ef32a23e35d4fba6)
1*7ab4cc98Skettenis /*	$OpenBSD: aplmbox.c,v 1.6 2023/07/23 11:17:49 kettenis Exp $	*/
25575003fSkettenis /*
35575003fSkettenis  * Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org>
45575003fSkettenis  *
55575003fSkettenis  * Permission to use, copy, modify, and distribute this software for any
65575003fSkettenis  * purpose with or without fee is hereby granted, provided that the above
75575003fSkettenis  * copyright notice and this permission notice appear in all copies.
85575003fSkettenis  *
95575003fSkettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
105575003fSkettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
115575003fSkettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
125575003fSkettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
135575003fSkettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
145575003fSkettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
155575003fSkettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
165575003fSkettenis  */
175575003fSkettenis 
185575003fSkettenis #include <sys/param.h>
195575003fSkettenis #include <sys/systm.h>
205575003fSkettenis #include <sys/device.h>
215575003fSkettenis #include <sys/malloc.h>
225575003fSkettenis 
235575003fSkettenis #include <machine/bus.h>
245575003fSkettenis #include <machine/fdt.h>
255575003fSkettenis 
265575003fSkettenis #include <dev/ofw/openfirm.h>
275575003fSkettenis #include <dev/ofw/ofw_misc.h>
28*7ab4cc98Skettenis #include <dev/ofw/ofw_power.h>
295575003fSkettenis #include <dev/ofw/fdt.h>
305575003fSkettenis 
315575003fSkettenis #include <arm64/dev/aplmbox.h>
325575003fSkettenis 
335575003fSkettenis #define MBOX_A2I_CTRL		0x110
345575003fSkettenis #define  MBOX_A2I_CTRL_FULL	(1 << 16)
355575003fSkettenis #define MBOX_I2A_CTRL		0x114
365575003fSkettenis #define  MBOX_I2A_CTRL_EMPTY	(1 << 17)
375575003fSkettenis #define MBOX_A2I_SEND0		0x800
385575003fSkettenis #define MBOX_A2I_SEND1		0x808
395575003fSkettenis #define MBOX_I2A_RECV0		0x830
405575003fSkettenis #define MBOX_I2A_RECV1		0x838
415575003fSkettenis 
425575003fSkettenis #define HREAD4(sc, reg)							\
435575003fSkettenis 	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
445575003fSkettenis #define HREAD8(sc, reg)							\
455575003fSkettenis 	(bus_space_read_8((sc)->sc_iot, (sc)->sc_ioh, (reg)))
465575003fSkettenis #define HWRITE4(sc, reg, val)						\
475575003fSkettenis 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
485575003fSkettenis #define HWRITE8(sc, reg, val)						\
495575003fSkettenis 	bus_space_write_8((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
505575003fSkettenis 
515575003fSkettenis struct aplmbox_softc {
525575003fSkettenis 	struct device		sc_dev;
535575003fSkettenis 	bus_space_tag_t		sc_iot;
545575003fSkettenis 	bus_space_handle_t	sc_ioh;
555575003fSkettenis 
565575003fSkettenis 	void			*sc_ih;
575575003fSkettenis 	void			(*sc_rx_callback)(void *);
585575003fSkettenis 	void			*sc_rx_arg;
595575003fSkettenis 
605575003fSkettenis 	struct mbox_device	sc_md;
615575003fSkettenis };
625575003fSkettenis 
635575003fSkettenis int	aplmbox_match(struct device *, void *, void *);
645575003fSkettenis void	aplmbox_attach(struct device *, struct device *, void *);
655575003fSkettenis 
665575003fSkettenis const struct cfattach aplmbox_ca = {
675575003fSkettenis 	sizeof (struct aplmbox_softc), aplmbox_match, aplmbox_attach
685575003fSkettenis };
695575003fSkettenis 
705575003fSkettenis struct cfdriver aplmbox_cd = {
715575003fSkettenis 	NULL, "aplmbox", DV_DULL
725575003fSkettenis };
735575003fSkettenis 
745575003fSkettenis int	aplmbox_intr(void *);
755575003fSkettenis void	*aplmbox_channel(void *, uint32_t *, struct mbox_client *);
765575003fSkettenis int	aplmbox_send(void *, const void *, size_t);
775575003fSkettenis int	aplmbox_recv(void *, void *, size_t);
785575003fSkettenis 
795575003fSkettenis int
aplmbox_match(struct device * parent,void * match,void * aux)805575003fSkettenis aplmbox_match(struct device *parent, void *match, void *aux)
815575003fSkettenis {
825575003fSkettenis 	struct fdt_attach_args *faa = aux;
835575003fSkettenis 
84bcf979e4Skettenis 	return (OF_is_compatible(faa->fa_node, "apple,asc-mailbox") ||
85bcf979e4Skettenis 	    OF_is_compatible(faa->fa_node, "apple,asc-mailbox-v4"));
865575003fSkettenis }
875575003fSkettenis 
885575003fSkettenis void
aplmbox_attach(struct device * parent,struct device * self,void * aux)895575003fSkettenis aplmbox_attach(struct device *parent, struct device *self, void *aux)
905575003fSkettenis {
915575003fSkettenis 	struct aplmbox_softc *sc = (struct aplmbox_softc *)self;
925575003fSkettenis 	struct fdt_attach_args *faa = aux;
935575003fSkettenis 	int idx;
945575003fSkettenis 
955575003fSkettenis 	if (faa->fa_nreg < 1) {
965575003fSkettenis 		printf(": no registers\n");
975575003fSkettenis 		return;
985575003fSkettenis 	}
995575003fSkettenis 
1005575003fSkettenis 	sc->sc_iot = faa->fa_iot;
1015575003fSkettenis 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
1025575003fSkettenis 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
1035575003fSkettenis 		printf(": can't map registers\n");
1045575003fSkettenis 		return;
1055575003fSkettenis 	}
1065575003fSkettenis 
1075575003fSkettenis 	idx = OF_getindex(faa->fa_node, "recv-not-empty", "interrupt-names");
1085575003fSkettenis 	if (idx > 0) {
1095575003fSkettenis 		sc->sc_ih = fdt_intr_establish_idx(faa->fa_node, idx, IPL_BIO,
1105575003fSkettenis 		    aplmbox_intr, sc, sc->sc_dev.dv_xname);
1115575003fSkettenis 	}
1125575003fSkettenis 
1135575003fSkettenis 	printf("\n");
1145575003fSkettenis 
115*7ab4cc98Skettenis 	power_domain_enable(faa->fa_node);
116*7ab4cc98Skettenis 
1175575003fSkettenis 	sc->sc_md.md_node = faa->fa_node;
1185575003fSkettenis 	sc->sc_md.md_cookie = sc;
1195575003fSkettenis 	sc->sc_md.md_channel = aplmbox_channel;
1205575003fSkettenis 	sc->sc_md.md_send = aplmbox_send;
1215575003fSkettenis 	sc->sc_md.md_recv = aplmbox_recv;
1225575003fSkettenis 	mbox_register(&sc->sc_md);
1235575003fSkettenis }
1245575003fSkettenis 
1255575003fSkettenis int
aplmbox_intr(void * arg)1265575003fSkettenis aplmbox_intr(void *arg)
1275575003fSkettenis {
1285575003fSkettenis 	struct aplmbox_softc *sc = arg;
1295575003fSkettenis 	uint32_t ctrl;
1305575003fSkettenis 
1315575003fSkettenis 	ctrl = HREAD4(sc, MBOX_I2A_CTRL);
1325575003fSkettenis 	if (ctrl & MBOX_I2A_CTRL_EMPTY)
1335575003fSkettenis 		return 0;
1345575003fSkettenis 
1355575003fSkettenis 	if (sc->sc_rx_callback) {
1365575003fSkettenis 		sc->sc_rx_callback(sc->sc_rx_arg);
1375575003fSkettenis 	} else {
1385575003fSkettenis 		printf("%s: 0x%016llx 0x%016llx\n", sc->sc_dev.dv_xname,
1395575003fSkettenis 		    HREAD8(sc, MBOX_I2A_RECV0), HREAD8(sc, MBOX_I2A_RECV1));
1405575003fSkettenis 	}
1415575003fSkettenis 
1425575003fSkettenis 	return 1;
1435575003fSkettenis }
1445575003fSkettenis 
1455575003fSkettenis void *
aplmbox_channel(void * cookie,uint32_t * cells,struct mbox_client * mc)1465575003fSkettenis aplmbox_channel(void *cookie, uint32_t *cells, struct mbox_client *mc)
1475575003fSkettenis {
1485575003fSkettenis 	struct aplmbox_softc *sc = cookie;
1495575003fSkettenis 
1505575003fSkettenis 	if (mc) {
1515575003fSkettenis 		sc->sc_rx_callback = mc->mc_rx_callback;
1525575003fSkettenis 		sc->sc_rx_arg = mc->mc_rx_arg;
1533b6109e0Skettenis 
1543b6109e0Skettenis 		if (mc->mc_flags & MC_WAKEUP)
1555dee5702Skettenis 			intr_set_wakeup(sc->sc_ih);
1565575003fSkettenis 	}
1575575003fSkettenis 
1585575003fSkettenis 	return sc;
1595575003fSkettenis }
1605575003fSkettenis 
1615575003fSkettenis int
aplmbox_send(void * cookie,const void * data,size_t len)1625575003fSkettenis aplmbox_send(void *cookie, const void *data, size_t len)
1635575003fSkettenis {
1645575003fSkettenis 	struct aplmbox_softc *sc = cookie;
1655575003fSkettenis 	const struct aplmbox_msg *msg = data;
1665575003fSkettenis 	uint32_t ctrl;
1675575003fSkettenis 
1685575003fSkettenis 	if (len != sizeof(struct aplmbox_msg))
1695575003fSkettenis 		return EINVAL;
1705575003fSkettenis 
1715575003fSkettenis 	ctrl = HREAD4(sc, MBOX_A2I_CTRL);
1725575003fSkettenis 	if (ctrl & MBOX_A2I_CTRL_FULL)
1735575003fSkettenis 		return EBUSY;
1745575003fSkettenis 
1755575003fSkettenis 	HWRITE8(sc, MBOX_A2I_SEND0, msg->data0);
1765575003fSkettenis 	HWRITE8(sc, MBOX_A2I_SEND1, msg->data1);
1775575003fSkettenis 
1785575003fSkettenis 	return 0;
1795575003fSkettenis }
1805575003fSkettenis 
1815575003fSkettenis int
aplmbox_recv(void * cookie,void * data,size_t len)1825575003fSkettenis aplmbox_recv(void *cookie, void *data, size_t len)
1835575003fSkettenis {
1845575003fSkettenis 	struct aplmbox_softc *sc = cookie;
1855575003fSkettenis 	struct aplmbox_msg *msg = data;
1865575003fSkettenis 	uint32_t ctrl;
1875575003fSkettenis 
1885575003fSkettenis 	if (len != sizeof(struct aplmbox_msg))
1895575003fSkettenis 		return EINVAL;
1905575003fSkettenis 
1915575003fSkettenis 	ctrl = HREAD4(sc, MBOX_I2A_CTRL);
1925575003fSkettenis 	if (ctrl & MBOX_I2A_CTRL_EMPTY)
193fb1acad1Skettenis 		return EWOULDBLOCK;
1945575003fSkettenis 
1955575003fSkettenis 	msg->data0 = HREAD8(sc, MBOX_I2A_RECV0);
1965575003fSkettenis 	msg->data1 = HREAD8(sc, MBOX_I2A_RECV1);
1975575003fSkettenis 
1985575003fSkettenis 	return 0;
1995575003fSkettenis }
200