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