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