xref: /openbsd-src/sys/arch/arm64/dev/aplmbox.c (revision 7ab4cc9835a16d0789381992ef32a23e35d4fba6)
1 /*	$OpenBSD: aplmbox.c,v 1.6 2023/07/23 11:17:49 kettenis Exp $	*/
2 /*
3  * Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/systm.h>
20 #include <sys/device.h>
21 #include <sys/malloc.h>
22 
23 #include <machine/bus.h>
24 #include <machine/fdt.h>
25 
26 #include <dev/ofw/openfirm.h>
27 #include <dev/ofw/ofw_misc.h>
28 #include <dev/ofw/ofw_power.h>
29 #include <dev/ofw/fdt.h>
30 
31 #include <arm64/dev/aplmbox.h>
32 
33 #define MBOX_A2I_CTRL		0x110
34 #define  MBOX_A2I_CTRL_FULL	(1 << 16)
35 #define MBOX_I2A_CTRL		0x114
36 #define  MBOX_I2A_CTRL_EMPTY	(1 << 17)
37 #define MBOX_A2I_SEND0		0x800
38 #define MBOX_A2I_SEND1		0x808
39 #define MBOX_I2A_RECV0		0x830
40 #define MBOX_I2A_RECV1		0x838
41 
42 #define HREAD4(sc, reg)							\
43 	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
44 #define HREAD8(sc, reg)							\
45 	(bus_space_read_8((sc)->sc_iot, (sc)->sc_ioh, (reg)))
46 #define HWRITE4(sc, reg, val)						\
47 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
48 #define HWRITE8(sc, reg, val)						\
49 	bus_space_write_8((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
50 
51 struct aplmbox_softc {
52 	struct device		sc_dev;
53 	bus_space_tag_t		sc_iot;
54 	bus_space_handle_t	sc_ioh;
55 
56 	void			*sc_ih;
57 	void			(*sc_rx_callback)(void *);
58 	void			*sc_rx_arg;
59 
60 	struct mbox_device	sc_md;
61 };
62 
63 int	aplmbox_match(struct device *, void *, void *);
64 void	aplmbox_attach(struct device *, struct device *, void *);
65 
66 const struct cfattach aplmbox_ca = {
67 	sizeof (struct aplmbox_softc), aplmbox_match, aplmbox_attach
68 };
69 
70 struct cfdriver aplmbox_cd = {
71 	NULL, "aplmbox", DV_DULL
72 };
73 
74 int	aplmbox_intr(void *);
75 void	*aplmbox_channel(void *, uint32_t *, struct mbox_client *);
76 int	aplmbox_send(void *, const void *, size_t);
77 int	aplmbox_recv(void *, void *, size_t);
78 
79 int
aplmbox_match(struct device * parent,void * match,void * aux)80 aplmbox_match(struct device *parent, void *match, void *aux)
81 {
82 	struct fdt_attach_args *faa = aux;
83 
84 	return (OF_is_compatible(faa->fa_node, "apple,asc-mailbox") ||
85 	    OF_is_compatible(faa->fa_node, "apple,asc-mailbox-v4"));
86 }
87 
88 void
aplmbox_attach(struct device * parent,struct device * self,void * aux)89 aplmbox_attach(struct device *parent, struct device *self, void *aux)
90 {
91 	struct aplmbox_softc *sc = (struct aplmbox_softc *)self;
92 	struct fdt_attach_args *faa = aux;
93 	int idx;
94 
95 	if (faa->fa_nreg < 1) {
96 		printf(": no registers\n");
97 		return;
98 	}
99 
100 	sc->sc_iot = faa->fa_iot;
101 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
102 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
103 		printf(": can't map registers\n");
104 		return;
105 	}
106 
107 	idx = OF_getindex(faa->fa_node, "recv-not-empty", "interrupt-names");
108 	if (idx > 0) {
109 		sc->sc_ih = fdt_intr_establish_idx(faa->fa_node, idx, IPL_BIO,
110 		    aplmbox_intr, sc, sc->sc_dev.dv_xname);
111 	}
112 
113 	printf("\n");
114 
115 	power_domain_enable(faa->fa_node);
116 
117 	sc->sc_md.md_node = faa->fa_node;
118 	sc->sc_md.md_cookie = sc;
119 	sc->sc_md.md_channel = aplmbox_channel;
120 	sc->sc_md.md_send = aplmbox_send;
121 	sc->sc_md.md_recv = aplmbox_recv;
122 	mbox_register(&sc->sc_md);
123 }
124 
125 int
aplmbox_intr(void * arg)126 aplmbox_intr(void *arg)
127 {
128 	struct aplmbox_softc *sc = arg;
129 	uint32_t ctrl;
130 
131 	ctrl = HREAD4(sc, MBOX_I2A_CTRL);
132 	if (ctrl & MBOX_I2A_CTRL_EMPTY)
133 		return 0;
134 
135 	if (sc->sc_rx_callback) {
136 		sc->sc_rx_callback(sc->sc_rx_arg);
137 	} else {
138 		printf("%s: 0x%016llx 0x%016llx\n", sc->sc_dev.dv_xname,
139 		    HREAD8(sc, MBOX_I2A_RECV0), HREAD8(sc, MBOX_I2A_RECV1));
140 	}
141 
142 	return 1;
143 }
144 
145 void *
aplmbox_channel(void * cookie,uint32_t * cells,struct mbox_client * mc)146 aplmbox_channel(void *cookie, uint32_t *cells, struct mbox_client *mc)
147 {
148 	struct aplmbox_softc *sc = cookie;
149 
150 	if (mc) {
151 		sc->sc_rx_callback = mc->mc_rx_callback;
152 		sc->sc_rx_arg = mc->mc_rx_arg;
153 
154 		if (mc->mc_flags & MC_WAKEUP)
155 			intr_set_wakeup(sc->sc_ih);
156 	}
157 
158 	return sc;
159 }
160 
161 int
aplmbox_send(void * cookie,const void * data,size_t len)162 aplmbox_send(void *cookie, const void *data, size_t len)
163 {
164 	struct aplmbox_softc *sc = cookie;
165 	const struct aplmbox_msg *msg = data;
166 	uint32_t ctrl;
167 
168 	if (len != sizeof(struct aplmbox_msg))
169 		return EINVAL;
170 
171 	ctrl = HREAD4(sc, MBOX_A2I_CTRL);
172 	if (ctrl & MBOX_A2I_CTRL_FULL)
173 		return EBUSY;
174 
175 	HWRITE8(sc, MBOX_A2I_SEND0, msg->data0);
176 	HWRITE8(sc, MBOX_A2I_SEND1, msg->data1);
177 
178 	return 0;
179 }
180 
181 int
aplmbox_recv(void * cookie,void * data,size_t len)182 aplmbox_recv(void *cookie, void *data, size_t len)
183 {
184 	struct aplmbox_softc *sc = cookie;
185 	struct aplmbox_msg *msg = data;
186 	uint32_t ctrl;
187 
188 	if (len != sizeof(struct aplmbox_msg))
189 		return EINVAL;
190 
191 	ctrl = HREAD4(sc, MBOX_I2A_CTRL);
192 	if (ctrl & MBOX_I2A_CTRL_EMPTY)
193 		return EWOULDBLOCK;
194 
195 	msg->data0 = HREAD8(sc, MBOX_I2A_RECV0);
196 	msg->data1 = HREAD8(sc, MBOX_I2A_RECV1);
197 
198 	return 0;
199 }
200