xref: /netbsd-src/sys/arch/arm/apple/apple_mbox.c (revision 09966de28c106fef44191dd94de4614a6a5d0a86)
1 /*	$NetBSD: apple_mbox.c,v 1.1 2022/04/27 08:06:20 skrll Exp $	*/
2 /*	$OpenBSD: apple_mbox.c,v 1.2 2022/01/04 20:55:48 kettenis Exp $	*/
3 
4 /*-
5  * Copyright (c) 2022 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Nick Hudson
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org>
35  *
36  * Permission to use, copy, modify, and distribute this software for any
37  * purpose with or without fee is hereby granted, provided that the above
38  * copyright notice and this permission notice appear in all copies.
39  *
40  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
41  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
42  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
43  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
44  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
45  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
46  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
47  */
48 
49 #include <sys/cdefs.h>
50 __KERNEL_RCSID(0, "$NetBSD: apple_mbox.c,v 1.1 2022/04/27 08:06:20 skrll Exp $");
51 
52 #include <sys/param.h>
53 #include <sys/bus.h>
54 #include <sys/device.h>
55 
56 #include <dev/fdt/fdtvar.h>
57 
58 #include <arm/apple/apple_mbox.h>
59 
60 #define MBOX_A2I_CTRL		0x110
61 #define  MBOX_A2I_CTRL_FULL	__BIT(16)
62 #define MBOX_I2A_CTRL		0x114
63 #define  MBOX_I2A_CTRL_EMPTY	__BIT(17)
64 #define MBOX_A2I_SEND0		0x800
65 #define MBOX_A2I_SEND1		0x808
66 #define MBOX_I2A_RECV0		0x830
67 #define MBOX_I2A_RECV1		0x838
68 
69 #define MBOX_READ4(sc, reg)							\
70 	(bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)))
71 #define MBOX_READ8(sc, reg)							\
72 	(bus_space_read_8((sc)->sc_bst, (sc)->sc_bsh, (reg)))
73 #define MBOX_WRITE4(sc, reg, val)						\
74 	bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
75 #define MBOX_WRITE8(sc, reg, val)						\
76 	bus_space_write_8((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
77 
78 static int apple_mbox_intr(void *);
79 
80 static struct mbox_interrupt {
81 	const char *mi_name;
82 	bool mi_claim;
83 	int (*mi_handler)(void *);
84 } mbox_interrupts[] = {
85 	{
86 		.mi_name = "send-empty",
87 		.mi_claim = false,
88 		.mi_handler = apple_mbox_intr,
89 	},
90 	{
91 		.mi_name = "send-not-empty",
92 		.mi_claim = false,
93 	},
94 	{
95 		.mi_name = "recv-empty",
96 		.mi_claim = false,
97 	},
98 	{
99 		.mi_name = "recv-not-empty",
100 		.mi_claim = true,
101 		.mi_handler = apple_mbox_intr,
102 	},
103 };
104 
105 struct apple_mbox_softc {
106 	device_t sc_dev;
107 	int sc_phandle;
108 	bus_space_tag_t sc_bst;
109 	bus_space_handle_t sc_bsh;
110 
111 	void *sc_intr[__arraycount(mbox_interrupts)];
112 	void (*sc_rx_callback)(void *);
113 	void *sc_rx_arg;
114 
115 //	struct fdtbus_mbox_device sc_md;
116 };
117 
118 static const struct device_compatible_entry compat_data[] = {
119 	{ .compat = "apple,asc-mailbox" },
120 	{ .compat = "apple,asc-mailbox-v4" },
121 	DEVICE_COMPAT_EOL
122 };
123 
124 
125 static int
apple_mbox_intr(void * arg)126 apple_mbox_intr(void *arg)
127 {
128 	struct apple_mbox_softc const *sc = arg;
129 	const uint32_t ctrl = MBOX_READ4(sc, MBOX_I2A_CTRL);
130 
131 	if (ctrl & MBOX_I2A_CTRL_EMPTY)
132 		return 0;
133 
134 	if (sc->sc_rx_callback) {
135 		sc->sc_rx_callback(sc->sc_rx_arg);
136 	} else {
137 		printf("%s: 0x%016" PRIx64 "0x%016" PRIx64 "\n",
138 		    device_xname(sc->sc_dev),
139 		    MBOX_READ8(sc, MBOX_I2A_RECV0),
140 		    MBOX_READ8(sc, MBOX_I2A_RECV1));
141 	}
142 
143 	return 1;
144 }
145 
146 static void *
apple_mbox_acquire(device_t dev,const void * cells,size_t len,void (* cb)(void *),void * arg)147 apple_mbox_acquire(device_t dev, const void *cells, size_t len,
148     void (*cb)(void *), void *arg)
149 {
150 	struct apple_mbox_softc * const sc = device_private(dev);
151 
152 	if (sc->sc_rx_callback == NULL && sc->sc_rx_arg == NULL) {
153 		sc->sc_rx_callback = cb;
154 		sc->sc_rx_arg = arg;
155 
156 		return sc;
157 	}
158 
159 	return NULL;
160 }
161 
162 static void
apple_mbox_release(device_t dev,void * priv)163 apple_mbox_release(device_t dev, void *priv)
164 {
165 	struct apple_mbox_softc * const sc = device_private(dev);
166 
167 	KASSERT(sc == priv);
168 
169 	sc->sc_rx_callback = NULL;
170 	sc->sc_rx_arg = NULL;
171 }
172 
173 static int
apple_mbox_send(device_t dev,void * priv,const void * data,size_t len)174 apple_mbox_send(device_t dev, void *priv, const void *data, size_t len)
175 {
176 	struct apple_mbox_softc * const sc = device_private(dev);
177 	const struct apple_mbox_msg *msg = data;
178 
179 	KASSERT(sc == priv);
180 
181 	if (len != sizeof(struct apple_mbox_msg))
182 		return EINVAL;
183 
184 
185 	uint32_t ctrl = MBOX_READ4(sc, MBOX_A2I_CTRL);
186 	if (ctrl & MBOX_A2I_CTRL_FULL)
187 		return EBUSY;
188 
189 	MBOX_WRITE8(sc, MBOX_A2I_SEND0, msg->data0);
190 	MBOX_WRITE8(sc, MBOX_A2I_SEND1, msg->data1);
191 
192 	return 0;
193 }
194 
195 static int
apple_mbox_recv(device_t dev,void * priv,void * data,size_t len)196 apple_mbox_recv(device_t dev, void *priv, void *data, size_t len)
197 {
198 	struct apple_mbox_softc * const sc = device_private(dev);
199 	struct apple_mbox_msg *msg = data;
200 
201 	KASSERT(sc == priv);
202 	if (len != sizeof(struct apple_mbox_msg))
203 		return EINVAL;
204 
205 	uint32_t ctrl = MBOX_READ4(sc, MBOX_I2A_CTRL);
206 	if (ctrl & MBOX_I2A_CTRL_EMPTY)
207 		return EAGAIN;
208 
209 	msg->data0 = MBOX_READ8(sc, MBOX_I2A_RECV0);
210 	msg->data1 = MBOX_READ8(sc, MBOX_I2A_RECV1);
211 
212 	return 0;
213 }
214 
215 
216 static int
apple_mbox_match(device_t parent,cfdata_t cf,void * aux)217 apple_mbox_match(device_t parent, cfdata_t cf, void *aux)
218 {
219 	struct fdt_attach_args * const faa = aux;
220 
221 	return of_compatible_match(faa->faa_phandle, compat_data);
222 }
223 
224 static void
apple_mbox_attach(device_t parent,device_t self,void * aux)225 apple_mbox_attach(device_t parent, device_t self, void *aux)
226 {
227 	struct apple_mbox_softc * const sc = device_private(self);
228 	struct fdt_attach_args * const faa = aux;
229 	const int phandle = faa->faa_phandle;
230 	bus_addr_t addr;
231 	bus_size_t size;
232 
233 	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
234 		aprint_error(": couldn't get registers\n");
235 		return;
236 	}
237 
238 	sc->sc_dev = self;
239 	sc->sc_rx_callback = NULL;
240 	sc->sc_rx_arg = NULL;
241 	sc->sc_bst = faa->faa_bst;
242 	if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
243 		aprint_error(": couldn't map registers\n");
244 		return;
245 	}
246 
247 	aprint_naive("\n");
248 	aprint_normal(": Apple Mailbox\n");
249 
250 	for (size_t i = 0; i < __arraycount(mbox_interrupts); i++) {
251 		struct mbox_interrupt *mi = &mbox_interrupts[i];
252 
253 		if (!mi->mi_claim)
254 			continue;
255 
256 		int index;
257 		int err = fdtbus_get_index(phandle, "interrupt-names",
258 		    mi->mi_name, &index);
259 		if (err != 0) {
260 			aprint_error_dev(self,
261 			    "couldn't get %s interrupt index\n", mi->mi_name);
262 			continue;
263 		}
264 
265 		char istr[128];
266 		if (!fdtbus_intr_str(phandle, index, istr, sizeof(istr))) {
267 			aprint_error_dev(self,
268 			    "couldn't decode %s interrupt\n", mi->mi_name);
269 			continue;
270 		}
271 
272 		sc->sc_intr[i] = fdtbus_intr_establish_xname(phandle, index,
273 		    IPL_VM, FDT_INTR_MPSAFE, mi->mi_handler, sc,
274 		    device_xname(self));
275 		if (sc->sc_intr[i] == NULL) {
276 			aprint_error_dev(self,
277 			    "couldn't establish %s interrupt\n", mi->mi_name);
278 			continue;
279 		}
280 
281 		aprint_normal_dev(self, "'%s' interrupting on %s\n",
282 		    mi->mi_name, istr);
283 	}
284 
285 	static struct fdtbus_mbox_controller_func funcs = {
286 		.mc_acquire = apple_mbox_acquire,
287 		.mc_release = apple_mbox_release,
288 		.mc_send = apple_mbox_send,
289 		.mc_recv = apple_mbox_recv,
290 	};
291 
292 	int error = fdtbus_register_mbox_controller(self, phandle, &funcs);
293 	if (error) {
294 		aprint_error_dev(self, "couldn't register mailbox\n");
295 		goto fail_register;
296 	}
297 	return;
298 
299 fail_register:
300 	for (size_t i = 0; i < __arraycount(mbox_interrupts); i++) {
301 		if (sc->sc_intr[i] != NULL) {
302 			fdtbus_intr_disestablish(phandle, sc->sc_intr[i]);
303 		}
304 	}
305 
306 	return;
307 }
308 
309 CFATTACH_DECL_NEW(apple_mbox, sizeof(struct apple_mbox_softc),
310     apple_mbox_match, apple_mbox_attach, NULL, NULL);
311