1 /* $NetBSD: apple_smc.c,v 1.1 2022/05/10 08:09:57 skrll Exp $ */ 2 /* $OpenBSD: apple_smc.c,v 1.11 2022/03/25 15:52:03 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/param.h> 50 51 #include <sys/device.h> 52 #include <sys/kernel.h> 53 #include <sys/kmem.h> 54 55 #include <dev/fdt/fdtvar.h> 56 57 #include <arm/apple/apple_rtkit.h> 58 59 extern void (*cpuresetfn)(void); 60 extern void (*powerdownfn)(void); 61 62 /* SMC mailbox endpoint */ 63 #define SMC_EP 32 64 65 /* SMC commands */ 66 #define SMC_READ_KEY 0x10 67 #define SMC_WRITE_KEY 0x11 68 #define SMC_GET_KEY_BY_INDEX 0x12 69 #define SMC_GET_KEY_INFO 0x13 70 #define SMC_GET_SRAM_ADDR 0x17 71 #define SMC_SRAM_SIZE 0x4000 72 73 #define SMC_DATA __BITS(63, 32) 74 #define SMC_WLEN __BITS(31, 24) 75 #define SMC_LENGTH __BITS(23, 16) 76 #define SMC_ID __BITS(15, 12) 77 #define SMC_CMD __BITS(7, 0) 78 79 /* SMC errors */ 80 #define SMC_ERROR_MASK __BITS(7, 0) 81 #define SMC_ERROR(d) __SHIFTOUT((d), SMC_ERROR_MASK) 82 #define SMC_OK 0x00 83 #define SMC_KEYNOTFOUND 0x84 84 85 /* SMC keys */ 86 #define SMC_KEY(s) ((s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3]) 87 88 struct smc_key_info { 89 uint8_t size; 90 uint8_t type[4]; 91 uint8_t flags; 92 }; 93 94 /* SMC GPIO commands */ 95 #define SMC_GPIO_CMD_OUTPUT (0x01 << 24) 96 97 /* RTC related constants */ 98 #define RTC_OFFSET_LEN 6 99 #define SMC_CLKM_LEN 6 100 101 #define APLSMC_BE __BIT(0) 102 #define APLSMC_HIDDEN __BIT(1) 103 104 #define APLSMC_MAX_SENSORS 19 105 106 struct apple_smc_softc { 107 device_t sc_dev; 108 bus_space_tag_t sc_bst; 109 bus_space_handle_t sc_bsh; 110 bus_space_handle_t sc_sram_bsh; 111 112 struct rtkit_state *sc_rs; 113 uint8_t sc_msgid; 114 uint64_t sc_data; 115 116 kmutex_t sc_mutex; 117 kcondvar_t sc_cv; 118 bool sc_done; 119 120 }; 121 122 struct apple_smc_gpio_pin { 123 u_int pin_no; 124 u_int pin_flags; 125 bool pin_actlo; 126 }; 127 128 struct apple_smc_softc *apple_smc_sc; 129 130 131 void apple_smc_callback(void *, uint64_t); 132 int apple_smc_send_cmd(struct apple_smc_softc *, uint8_t, uint32_t, uint16_t); 133 int apple_smc_wait_cmd(struct apple_smc_softc *sc); 134 int apple_smc_read_key(struct apple_smc_softc *, uint32_t, void *, size_t); 135 136 137 static const struct device_compatible_entry compat_data[] = { 138 { .compat = "apple,smc" }, 139 DEVICE_COMPAT_EOL 140 }; 141 142 void 143 apple_smc_callback(void *arg, uint64_t data) 144 { 145 struct apple_smc_softc * const sc = arg; 146 147 mutex_enter(&sc->sc_mutex); 148 sc->sc_data = data; 149 sc->sc_done = true; 150 cv_signal(&sc->sc_cv); 151 mutex_exit(&sc->sc_mutex); 152 } 153 154 int 155 apple_smc_send_cmd(struct apple_smc_softc *sc, uint8_t cmd, uint32_t key, 156 uint16_t len) 157 { 158 uint64_t data = 159 __SHIFTIN(key, SMC_DATA) | 160 __SHIFTIN(cmd, SMC_CMD) | 161 __SHIFTIN(len, SMC_LENGTH) | 162 __SHIFTIN((sc->sc_msgid++ & 0xf), SMC_ID) 163 ; 164 165 return rtkit_send_endpoint(sc->sc_rs, SMC_EP, data); 166 } 167 168 int 169 apple_smc_wait_cmd(struct apple_smc_softc *sc) 170 { 171 int error; 172 if (cold) { 173 int timo; 174 175 /* Poll for completion. */ 176 for (timo = 1000; timo > 0; timo--) { 177 error = rtkit_poll(sc->sc_rs); 178 if (error == 0) 179 return 0; 180 delay(10); 181 } 182 183 return EWOULDBLOCK; 184 } 185 186 mutex_enter(&sc->sc_mutex); 187 sc->sc_done = false; 188 while (!sc->sc_done) { 189 error = cv_timedwait(&sc->sc_cv, &sc->sc_mutex, hz / 10); 190 if (error) 191 break; 192 } 193 mutex_exit(&sc->sc_mutex); 194 195 return error; 196 } 197 198 int 199 apple_smc_read_key(struct apple_smc_softc *sc, uint32_t key, void *data, size_t len) 200 { 201 int error; 202 203 apple_smc_send_cmd(sc, SMC_READ_KEY, key, len); 204 error = apple_smc_wait_cmd(sc); 205 if (error) 206 return error; 207 switch (SMC_ERROR(sc->sc_data)) { 208 case SMC_OK: 209 break; 210 case SMC_KEYNOTFOUND: 211 return EINVAL; 212 break; 213 default: 214 return EIO; 215 break; 216 } 217 218 len = MIN(len, (sc->sc_data >> 16) & 0xffff); 219 if (len > sizeof(uint32_t)) { 220 bus_space_read_region_1(sc->sc_bst, sc->sc_sram_bsh, 0, 221 data, len); 222 } else { 223 uint32_t tmp = (sc->sc_data >> 32); 224 memcpy(data, &tmp, len); 225 } 226 227 return 0; 228 } 229 230 static int 231 apple_smc_write_key(struct apple_smc_softc *sc, uint32_t key, void *data, size_t len) 232 { 233 bus_space_write_region_1(sc->sc_bst, sc->sc_sram_bsh, 0, data, len); 234 bus_space_barrier(sc->sc_bst, sc->sc_sram_bsh, 0, len, 235 BUS_SPACE_BARRIER_WRITE); 236 apple_smc_send_cmd(sc, SMC_WRITE_KEY, key, len); 237 238 return apple_smc_wait_cmd(sc); 239 } 240 241 static void * 242 apple_smc_gpio_acquire(device_t dev, const void *data, size_t len, int flags) 243 { 244 struct apple_smc_gpio_pin *pin; 245 const u_int *gpio = data; 246 247 if (len != 12) 248 return NULL; 249 250 const u_int pinno = be32toh(gpio[1]); 251 const bool actlo = be32toh(gpio[2]) & 1; 252 253 if (pinno >= 256) 254 return NULL; 255 256 pin = kmem_alloc(sizeof(*pin), KM_SLEEP); 257 pin->pin_no = pinno; 258 pin->pin_flags = flags; 259 pin->pin_actlo = actlo; 260 261 return pin; 262 } 263 264 265 static void 266 apple_smc_gpio_release(device_t dev, void *priv) 267 { 268 struct apple_smc_gpio_pin *pin = priv; 269 270 kmem_free(pin, sizeof(*pin)); 271 } 272 273 static void 274 apple_smc_gpio_write(device_t dev, void *priv, int val, bool raw) 275 { 276 struct apple_smc_softc * const sc = device_private(dev); 277 struct apple_smc_gpio_pin *pin = priv; 278 const u_int pn = pin->pin_no; 279 static const char *digits = "0123456789abcdef"; 280 uint32_t key = SMC_KEY("gP\0\0"); 281 uint32_t data; 282 283 key |= __SHIFTIN(digits[__SHIFTOUT(pn, __BITS(3, 0))], __BITS(7, 0)); 284 key |= __SHIFTIN(digits[__SHIFTOUT(pn, __BITS(7, 4))], __BITS(15, 8)); 285 286 if (pin->pin_actlo) 287 val = !val; 288 data = SMC_GPIO_CMD_OUTPUT | !!val; 289 290 apple_smc_write_key(sc, key, &data, sizeof(data)); 291 } 292 293 static int 294 apple_smc_match(device_t parent, cfdata_t cf, void *aux) 295 { 296 struct fdt_attach_args * const faa = aux; 297 298 return of_compatible_match(faa->faa_phandle, compat_data); 299 } 300 301 302 static struct fdtbus_gpio_controller_func apple_smc_gpio_funcs = { 303 .acquire = apple_smc_gpio_acquire, 304 .release = apple_smc_gpio_release, 305 // .read = apple_smc_gpio_read, 306 .write = apple_smc_gpio_write 307 }; 308 309 310 static void 311 apple_smc_attach(device_t parent, device_t self, void *aux) 312 { 313 struct apple_smc_softc * const sc = device_private(self); 314 struct fdt_attach_args * const faa = aux; 315 const int phandle = faa->faa_phandle; 316 bus_addr_t addr; 317 bus_size_t size; 318 int error; 319 320 if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { 321 aprint_error(": couldn't get registers\n"); 322 return; 323 } 324 325 sc->sc_dev = self; 326 sc->sc_bst = faa->faa_bst; 327 if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { 328 aprint_error(": couldn't map registers\n"); 329 return; 330 } 331 332 mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE); 333 cv_init(&sc->sc_cv, "applesmc"); 334 335 sc->sc_rs = rtkit_init(phandle, NULL); 336 if (sc->sc_rs == NULL) { 337 aprint_error(": can't map mailbox channel\n"); 338 return; 339 } 340 341 error = rtkit_boot(sc->sc_rs); 342 if (error) { 343 aprint_error(": can't boot firmware\n"); 344 return; 345 } 346 347 error = rtkit_start_endpoint(sc->sc_rs, SMC_EP, apple_smc_callback, sc); 348 if (error) { 349 aprint_error(": can't start SMC endpoint\n"); 350 return; 351 } 352 353 apple_smc_send_cmd(sc, SMC_GET_SRAM_ADDR, 0, 0); 354 error = apple_smc_wait_cmd(sc); 355 if (error) { 356 aprint_error(": can't get SRAM address\n"); 357 return; 358 } 359 360 if (bus_space_map(sc->sc_bst, sc->sc_data, SMC_SRAM_SIZE, 0, 361 &sc->sc_sram_bsh)) { 362 aprint_error(": can't map SRAM\n"); 363 return; 364 } 365 366 aprint_naive("\n"); 367 aprint_normal(": Apple SMC\n"); 368 369 apple_smc_sc = sc; 370 371 const int gpio = of_find_firstchild_byname(phandle, "gpio"); 372 if (gpio > 0) { 373 fdtbus_register_gpio_controller(self, gpio, 374 &apple_smc_gpio_funcs); 375 } 376 } 377 378 379 CFATTACH_DECL_NEW(apple_rtkitsmc, sizeof(struct apple_smc_softc), 380 apple_smc_match, apple_smc_attach, NULL, NULL); 381