1 /* $OpenBSD: aplsmc.c,v 1.12 2022/06/12 16:00:12 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/device.h> 21 #include <sys/sensors.h> 22 23 #include <machine/apmvar.h> 24 #include <machine/bus.h> 25 #include <machine/fdt.h> 26 27 #include <dev/clock_subr.h> 28 #include <dev/ofw/openfirm.h> 29 #include <dev/ofw/ofw_gpio.h> 30 #include <dev/ofw/ofw_misc.h> 31 #include <dev/ofw/fdt.h> 32 33 #include <arm64/dev/aplmbox.h> 34 #include <arm64/dev/rtkit.h> 35 36 #include "apm.h" 37 38 extern void (*cpuresetfn)(void); 39 extern void (*powerdownfn)(void); 40 41 /* SMC mailbox endpoint */ 42 #define SMC_EP 32 43 44 /* SMC commands */ 45 #define SMC_READ_KEY 0x10 46 #define SMC_WRITE_KEY 0x11 47 #define SMC_GET_KEY_BY_INDEX 0x12 48 #define SMC_GET_KEY_INFO 0x13 49 #define SMC_GET_SRAM_ADDR 0x17 50 #define SMC_SRAM_SIZE 0x4000 51 52 /* SMC errors */ 53 #define SMC_ERROR(d) ((d) & 0xff) 54 #define SMC_OK 0x00 55 #define SMC_KEYNOTFOUND 0x84 56 57 /* SMC keys */ 58 #define SMC_KEY(s) ((s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3]) 59 60 struct smc_key_info { 61 uint8_t size; 62 uint8_t type[4]; 63 uint8_t flags; 64 }; 65 66 /* SMC GPIO commands */ 67 #define SMC_GPIO_CMD_OUTPUT (0x01 << 24) 68 69 /* RTC related constants */ 70 #define RTC_OFFSET_LEN 6 71 #define SMC_CLKM_LEN 6 72 73 struct aplsmc_sensor { 74 const char *key; 75 const char *key_type; 76 enum sensor_type type; 77 int scale; 78 const char *desc; 79 int flags; 80 }; 81 82 #define APLSMC_BE (1 << 0) 83 #define APLSMC_HIDDEN (1 << 1) 84 85 #define APLSMC_MAX_SENSORS 19 86 87 struct aplsmc_softc { 88 struct device sc_dev; 89 bus_space_tag_t sc_iot; 90 bus_space_handle_t sc_ioh; 91 bus_space_handle_t sc_sram_ioh; 92 93 void *sc_ih; 94 95 struct rtkit_state *sc_rs; 96 uint8_t sc_msgid; 97 uint64_t sc_data; 98 99 struct gpio_controller sc_gc; 100 101 int sc_rtc_node; 102 struct todr_chip_handle sc_todr; 103 104 int sc_reboot_node; 105 106 struct aplsmc_sensor *sc_smcsensors[APLSMC_MAX_SENSORS]; 107 struct ksensor sc_sensors[APLSMC_MAX_SENSORS]; 108 int sc_nsensors; 109 struct ksensordev sc_sensordev; 110 }; 111 112 struct aplsmc_softc *aplsmc_sc; 113 114 #ifndef SMALL_KERNEL 115 116 struct aplsmc_sensor aplsmc_sensors[] = { 117 { "ACDI", "ui16", SENSOR_INDICATOR, 1, "power supply" }, 118 { "B0RM", "ui16", SENSOR_AMPHOUR, 1000, "remaining battery capacity", 119 APLSMC_BE }, 120 { "B0FC", "ui16", SENSOR_AMPHOUR, 1000, "last full battery capacity" }, 121 { "B0DC", "ui16", SENSOR_AMPHOUR, 1000, "battery design capacity" }, 122 { "B0AV", "ui16", SENSOR_VOLTS_DC, 1000, "battery" }, 123 { "B0CT", "ui16", SENSOR_INTEGER, 1, "battery discharge cycles" }, 124 { "B0TF", "ui16", SENSOR_INTEGER, 1, "battery time-to-full", 125 APLSMC_HIDDEN }, 126 { "B0TE", "ui16", SENSOR_INTEGER, 1, "battery time-to-empty", 127 APLSMC_HIDDEN }, 128 { "F0Ac", "flt ", SENSOR_FANRPM, 1, "" }, 129 { "ID0R", "flt ", SENSOR_AMPS, 1000000, "input" }, 130 { "PDTR", "flt ", SENSOR_WATTS, 1000000, "input" }, 131 { "PSTR", "flt ", SENSOR_WATTS, 1000000, "system" }, 132 { "TB0T", "flt ", SENSOR_TEMP, 1000000, "battery" }, 133 { "TCHP", "flt ", SENSOR_TEMP, 1000000, "charger" }, 134 { "TW0P", "flt ", SENSOR_TEMP, 1000000, "wireless" }, 135 { "Ts0P", "flt ", SENSOR_TEMP, 1000000, "palm rest" }, 136 { "Ts1P", "flt ", SENSOR_TEMP, 1000000, "palm rest" }, 137 { "VD0R", "flt ", SENSOR_VOLTS_DC, 1000000, "input" }, 138 }; 139 140 #endif 141 142 int aplsmc_match(struct device *, void *, void *); 143 void aplsmc_attach(struct device *, struct device *, void *); 144 145 const struct cfattach aplsmc_ca = { 146 sizeof (struct aplsmc_softc), aplsmc_match, aplsmc_attach 147 }; 148 149 struct cfdriver aplsmc_cd = { 150 NULL, "aplsmc", DV_DULL 151 }; 152 153 void aplsmc_callback(void *, uint64_t); 154 int aplsmc_send_cmd(struct aplsmc_softc *, uint16_t, uint32_t, uint16_t); 155 int aplsmc_wait_cmd(struct aplsmc_softc *sc); 156 int aplsmc_read_key(struct aplsmc_softc *, uint32_t, void *, size_t); 157 void aplsmc_refresh_sensors(void *); 158 int aplsmc_apminfo(struct apm_power_info *); 159 void aplsmc_set_pin(void *, uint32_t *, int); 160 int aplsmc_gettime(struct todr_chip_handle *, struct timeval *); 161 int aplsmc_settime(struct todr_chip_handle *, struct timeval *); 162 void aplsmc_reset(void); 163 void aplsmc_powerdown(void); 164 void aplsmc_reboot_attachhook(struct device *); 165 166 int 167 aplsmc_match(struct device *parent, void *match, void *aux) 168 { 169 struct fdt_attach_args *faa = aux; 170 171 return OF_is_compatible(faa->fa_node, "apple,smc"); 172 } 173 174 void 175 aplsmc_attach(struct device *parent, struct device *self, void *aux) 176 { 177 struct aplsmc_softc *sc = (struct aplsmc_softc *)self; 178 struct fdt_attach_args *faa = aux; 179 uint8_t data[SMC_CLKM_LEN]; 180 int error, node; 181 #ifndef SMALL_KERNEL 182 int i; 183 #endif 184 185 if (faa->fa_nreg < 1) { 186 printf(": no registers\n"); 187 return; 188 } 189 190 sc->sc_iot = faa->fa_iot; 191 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 192 faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 193 printf(": can't map registers\n"); 194 return; 195 } 196 197 sc->sc_rs = rtkit_init(faa->fa_node, NULL, NULL); 198 if (sc->sc_rs == NULL) { 199 printf(": can't map mailbox channel\n"); 200 return; 201 } 202 203 error = rtkit_boot(sc->sc_rs); 204 if (error) { 205 printf(": can't boot firmware\n"); 206 return; 207 } 208 209 error = rtkit_start_endpoint(sc->sc_rs, SMC_EP, aplsmc_callback, sc); 210 if (error) { 211 printf(": can't start SMC endpoint\n"); 212 return; 213 } 214 215 aplsmc_send_cmd(sc, SMC_GET_SRAM_ADDR, 0, 0); 216 error = aplsmc_wait_cmd(sc); 217 if (error) { 218 printf(": can't get SRAM address\n"); 219 return; 220 } 221 222 if (bus_space_map(sc->sc_iot, sc->sc_data, 223 SMC_SRAM_SIZE, 0, &sc->sc_sram_ioh)) { 224 printf(": can't map SRAM\n"); 225 return; 226 } 227 228 printf("\n"); 229 230 aplsmc_sc = sc; 231 232 node = OF_getnodebyname(faa->fa_node, "gpio"); 233 if (node) { 234 sc->sc_gc.gc_node = node; 235 sc->sc_gc.gc_cookie = sc; 236 sc->sc_gc.gc_set_pin = aplsmc_set_pin; 237 gpio_controller_register(&sc->sc_gc); 238 } 239 240 /* 241 * Only provide TODR implementation if the "CLKM" key is 242 * supported by the SMC firmware. 243 */ 244 error = aplsmc_read_key(sc, SMC_KEY("CLKM"), &data, SMC_CLKM_LEN); 245 node = OF_getnodebyname(faa->fa_node, "rtc"); 246 if (node && error == 0) { 247 sc->sc_rtc_node = node; 248 sc->sc_todr.cookie = sc; 249 sc->sc_todr.todr_gettime = aplsmc_gettime; 250 sc->sc_todr.todr_settime = aplsmc_settime; 251 todr_attach(&sc->sc_todr); 252 } 253 254 node = OF_getnodebyname(faa->fa_node, "reboot"); 255 if (node) { 256 sc->sc_reboot_node = node; 257 cpuresetfn = aplsmc_reset; 258 powerdownfn = aplsmc_powerdown; 259 config_mountroot(self, aplsmc_reboot_attachhook); 260 } 261 262 #ifndef SMALL_KERNEL 263 264 for (i = 0; i < nitems(aplsmc_sensors); i++) { 265 struct smc_key_info info; 266 267 aplsmc_send_cmd(sc, SMC_GET_KEY_INFO, 268 SMC_KEY(aplsmc_sensors[i].key), 0); 269 error = aplsmc_wait_cmd(sc); 270 if (error || SMC_ERROR(sc->sc_data) != SMC_OK) 271 continue; 272 273 bus_space_read_region_1(sc->sc_iot, sc->sc_sram_ioh, 0, 274 (uint8_t *)&info, sizeof(info)); 275 276 /* Skip if the key type doesn't match. */ 277 if (memcmp(aplsmc_sensors[i].key_type, info.type, 278 sizeof(info.type)) != 0) 279 continue; 280 281 if (sc->sc_nsensors >= APLSMC_MAX_SENSORS) { 282 printf("%s: maximum number of sensors exceeded\n", 283 sc->sc_dev.dv_xname); 284 break; 285 } 286 287 sc->sc_smcsensors[sc->sc_nsensors] = &aplsmc_sensors[i]; 288 strlcpy(sc->sc_sensors[sc->sc_nsensors].desc, 289 aplsmc_sensors[i].desc, sizeof(sc->sc_sensors[0].desc)); 290 sc->sc_sensors[sc->sc_nsensors].type = aplsmc_sensors[i].type; 291 if (!(aplsmc_sensors[i].flags & APLSMC_HIDDEN)) { 292 sensor_attach(&sc->sc_sensordev, 293 &sc->sc_sensors[sc->sc_nsensors]); 294 } 295 sc->sc_nsensors++; 296 } 297 298 aplsmc_refresh_sensors(sc); 299 300 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, 301 sizeof(sc->sc_sensordev.xname)); 302 sensordev_install(&sc->sc_sensordev); 303 sensor_task_register(sc, aplsmc_refresh_sensors, 5); 304 305 #if NAPM > 0 306 apm_setinfohook(aplsmc_apminfo); 307 #endif 308 309 #endif 310 } 311 312 void 313 aplsmc_callback(void *arg, uint64_t data) 314 { 315 struct aplsmc_softc *sc = arg; 316 317 sc->sc_data = data; 318 wakeup(&sc->sc_data); 319 } 320 321 int 322 aplsmc_send_cmd(struct aplsmc_softc *sc, uint16_t cmd, uint32_t key, 323 uint16_t len) 324 { 325 uint64_t data; 326 327 data = cmd; 328 data |= (uint64_t)len << 16; 329 data |= (uint64_t)key << 32; 330 data |= (sc->sc_msgid++ & 0xf) << 12; 331 332 return rtkit_send_endpoint(sc->sc_rs, SMC_EP, data); 333 } 334 335 int 336 aplsmc_wait_cmd(struct aplsmc_softc *sc) 337 { 338 if (cold) { 339 int error, timo; 340 341 /* Poll for completion. */ 342 for (timo = 1000; timo > 0; timo--) { 343 error = rtkit_poll(sc->sc_rs); 344 if (error == 0) 345 return 0; 346 delay(10); 347 } 348 349 return EWOULDBLOCK; 350 } 351 352 /* Sleep until the callback wakes us up. */ 353 return tsleep_nsec(&sc->sc_data, PWAIT, "apsmc", 10000000); 354 } 355 356 int 357 aplsmc_read_key(struct aplsmc_softc *sc, uint32_t key, void *data, size_t len) 358 { 359 int error; 360 361 aplsmc_send_cmd(sc, SMC_READ_KEY, key, len); 362 error = aplsmc_wait_cmd(sc); 363 if (error) 364 return error; 365 switch (SMC_ERROR(sc->sc_data)) { 366 case SMC_OK: 367 break; 368 case SMC_KEYNOTFOUND: 369 return EINVAL; 370 break; 371 default: 372 return EIO; 373 break; 374 } 375 376 len = min(len, (sc->sc_data >> 16) & 0xffff); 377 if (len > sizeof(uint32_t)) { 378 bus_space_read_region_1(sc->sc_iot, sc->sc_sram_ioh, 0, 379 data, len); 380 } else { 381 uint32_t tmp = (sc->sc_data >> 32); 382 memcpy(data, &tmp, len); 383 } 384 385 return 0; 386 } 387 388 int 389 aplsmc_write_key(struct aplsmc_softc *sc, uint32_t key, void *data, size_t len) 390 { 391 bus_space_write_region_1(sc->sc_iot, sc->sc_sram_ioh, 0, data, len); 392 bus_space_barrier(sc->sc_iot, sc->sc_sram_ioh, 0, len, 393 BUS_SPACE_BARRIER_WRITE); 394 aplsmc_send_cmd(sc, SMC_WRITE_KEY, key, len); 395 return aplsmc_wait_cmd(sc); 396 } 397 398 #ifndef SMALL_KERNEL 399 400 void 401 aplsmc_refresh_sensors(void *arg) 402 { 403 extern int hw_power; 404 struct aplsmc_softc *sc = arg; 405 struct aplsmc_sensor *sensor; 406 int64_t value; 407 uint32_t key; 408 int i, error; 409 410 for (i = 0; i < sc->sc_nsensors; i++) { 411 sensor = sc->sc_smcsensors[i]; 412 key = SMC_KEY(sensor->key); 413 414 if (strcmp(sensor->key_type, "ui8 ") == 0) { 415 uint8_t ui8; 416 417 error = aplsmc_read_key(sc, key, &ui8, sizeof(ui8)); 418 value = (int64_t)ui8 * sensor->scale; 419 } else if (strcmp(sensor->key_type, "ui16") == 0) { 420 uint16_t ui16; 421 422 error = aplsmc_read_key(sc, key, &ui16, sizeof(ui16)); 423 if (sensor->flags & APLSMC_BE) 424 ui16 = betoh16(ui16); 425 value = (int64_t)ui16 * sensor->scale; 426 } else if (strcmp(sensor->key_type, "flt ") == 0) { 427 uint32_t flt; 428 int64_t mant; 429 int sign, exp; 430 431 error = aplsmc_read_key(sc, key, &flt, sizeof(flt)); 432 if (sensor->flags & APLSMC_BE) 433 flt = betoh32(flt); 434 435 /* 436 * Convert floating-point to integer, trying 437 * to keep as much resolution as possible 438 * given the scaling factor for this sensor. 439 */ 440 sign = (flt >> 31) ? -1 : 1; 441 exp = ((flt >> 23) & 0xff) - 127; 442 mant = (flt & 0x7fffff) | 0x800000; 443 mant *= sensor->scale; 444 if (exp < 23) 445 value = sign * (mant >> (23 - exp)); 446 else 447 value = sign * (mant << (exp - 23)); 448 } 449 450 /* Apple reports temperatures in degC. */ 451 if (sensor->type == SENSOR_TEMP) 452 value += 273150000; 453 454 if (error) { 455 sc->sc_sensors[i].flags |= SENSOR_FUNKNOWN; 456 } else { 457 sc->sc_sensors[i].flags &= ~SENSOR_FUNKNOWN; 458 sc->sc_sensors[i].value = value; 459 } 460 461 if (strcmp(sensor->key, "ACDI") == 0) 462 hw_power = (value > 0); 463 } 464 } 465 466 #if NAPM > 0 467 468 int 469 aplsmc_apminfo(struct apm_power_info *info) 470 { 471 struct aplsmc_sensor *sensor; 472 struct ksensor *ksensor; 473 struct aplsmc_softc *sc = aplsmc_sc; 474 int remaining = -1, capacity = -1, i; 475 476 info->battery_state = APM_BATT_UNKNOWN; 477 info->ac_state = APM_AC_UNKNOWN; 478 info->battery_life = 0; 479 info->minutes_left = -1; 480 481 for (i = 0; i < sc->sc_nsensors; i++) { 482 sensor = sc->sc_smcsensors[i]; 483 ksensor = &sc->sc_sensors[i]; 484 485 if (ksensor->flags & SENSOR_FUNKNOWN) 486 continue; 487 488 if (strcmp(sensor->key, "ACDI") == 0) { 489 info->ac_state = ksensor->value ? 490 APM_AC_ON : APM_AC_OFF; 491 } else if (strcmp(sensor->key, "B0RM") == 0) 492 remaining = ksensor->value; 493 else if (strcmp(sensor->key, "B0FC") == 0) 494 capacity = ksensor->value; 495 else if ((strcmp(sensor->key, "B0TE") == 0) && 496 (ksensor->value != 0xffff)) 497 info->minutes_left = ksensor->value; 498 else if ((strcmp(sensor->key, "B0TF") == 0) && 499 (ksensor->value != 0xffff)) { 500 info->battery_state = APM_BATT_CHARGING; 501 info->minutes_left = ksensor->value; 502 } 503 } 504 505 /* calculate remaining battery if we have sane values */ 506 if (remaining > -1 && capacity > 0) { 507 info->battery_life = ((remaining * 100) / capacity); 508 if (info->battery_state != APM_BATT_CHARGING) { 509 if (info->battery_life > 50) 510 info->battery_state = APM_BATT_HIGH; 511 else if (info->battery_life > 25) 512 info->battery_state = APM_BATT_LOW; 513 else 514 info->battery_state = APM_BATT_CRITICAL; 515 } 516 } 517 518 return 0; 519 } 520 521 #endif 522 #endif 523 524 void 525 aplsmc_set_pin(void *cookie, uint32_t *cells, int val) 526 { 527 struct aplsmc_softc *sc = cookie; 528 static char *digits = "0123456789abcdef"; 529 uint32_t pin = cells[0]; 530 uint32_t flags = cells[1]; 531 uint32_t key = SMC_KEY("gP\0\0"); 532 uint32_t data; 533 534 KASSERT(pin < 256); 535 536 key |= (digits[(pin >> 0) & 0xf] << 0); 537 key |= (digits[(pin >> 4) & 0xf] << 8); 538 539 if (flags & GPIO_ACTIVE_LOW) 540 val = !val; 541 data = SMC_GPIO_CMD_OUTPUT | !!val; 542 543 aplsmc_write_key(sc, key, &data, sizeof(data)); 544 } 545 546 int 547 aplsmc_gettime(struct todr_chip_handle *handle, struct timeval *tv) 548 { 549 struct aplsmc_softc *sc = handle->cookie; 550 uint8_t data[8] = {}; 551 uint64_t offset, time; 552 int error; 553 554 error = nvmem_read_cell(sc->sc_rtc_node, "rtc_offset", &data, 555 RTC_OFFSET_LEN); 556 if (error) 557 return error; 558 offset = lemtoh64(data); 559 560 error = aplsmc_read_key(sc, SMC_KEY("CLKM"), &data, SMC_CLKM_LEN); 561 if (error) 562 return error; 563 time = lemtoh64(data) + offset; 564 565 tv->tv_sec = (time >> 15); 566 tv->tv_usec = (((time & 0x7fff) * 1000000) >> 15); 567 return 0; 568 } 569 570 int 571 aplsmc_settime(struct todr_chip_handle *handle, struct timeval *tv) 572 { 573 struct aplsmc_softc *sc = handle->cookie; 574 uint8_t data[8] = {}; 575 uint64_t offset, time; 576 int error; 577 578 error = aplsmc_read_key(sc, SMC_KEY("CLKM"), &data, SMC_CLKM_LEN); 579 if (error) 580 return error; 581 582 time = ((uint64_t)tv->tv_sec << 15); 583 time |= ((uint64_t)tv->tv_usec << 15) / 1000000; 584 offset = time - lemtoh64(data); 585 586 htolem64(data, offset); 587 return nvmem_write_cell(sc->sc_rtc_node, "rtc_offset", &data, 588 RTC_OFFSET_LEN); 589 } 590 591 void 592 aplsmc_reboot_attachhook(struct device *self) 593 { 594 struct aplsmc_softc *sc = (struct aplsmc_softc *)self; 595 uint8_t count = 0; 596 597 /* Reset error counters. */ 598 nvmem_write_cell(sc->sc_reboot_node, "boot_error_count", 599 &count, sizeof(count)); 600 nvmem_write_cell(sc->sc_reboot_node, "panic_count", 601 &count, sizeof(count)); 602 } 603 604 void 605 aplsmc_reset(void) 606 { 607 struct aplsmc_softc *sc = aplsmc_sc; 608 uint32_t key = SMC_KEY("MBSE"); 609 uint32_t rest = SMC_KEY("rest"); 610 uint32_t phra = SMC_KEY("phra"); 611 uint8_t boot_stage = 0; 612 613 aplsmc_write_key(sc, key, &rest, sizeof(rest)); 614 nvmem_write_cell(sc->sc_reboot_node, "boot_stage", 615 &boot_stage, sizeof(boot_stage)); 616 aplsmc_write_key(sc, key, &phra, sizeof(phra)); 617 } 618 619 void 620 aplsmc_powerdown(void) 621 { 622 struct aplsmc_softc *sc = aplsmc_sc; 623 uint32_t key = SMC_KEY("MBSE"); 624 uint32_t offw = SMC_KEY("offw"); 625 uint32_t off1 = SMC_KEY("off1"); 626 uint8_t boot_stage = 0; 627 uint8_t shutdown_flag = 1; 628 629 aplsmc_write_key(sc, key, &offw, sizeof(offw)); 630 nvmem_write_cell(sc->sc_reboot_node, "boot_stage", 631 &boot_stage, sizeof(boot_stage)); 632 nvmem_write_cell(sc->sc_reboot_node, "shutdown_flag", 633 &shutdown_flag, sizeof(shutdown_flag)); 634 aplsmc_write_key(sc, key, &off1, sizeof(off1)); 635 } 636