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
78static int apple_mbox_intr(void *);
79
80static 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
105struct 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
118static 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
125static int
126apple_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
146static void *
147apple_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
162static void
163apple_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
173static int
174apple_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
195static int
196apple_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
216static int
217apple_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
224static void
225apple_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
299fail_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
309CFATTACH_DECL_NEW(apple_mbox, sizeof(struct apple_mbox_softc),
310    apple_mbox_match, apple_mbox_attach, NULL, NULL);
311