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