1 /* $OpenBSD: aplsmc.c,v 1.28 2024/11/04 09:33:16 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/proc.h> 22 #include <sys/sensors.h> 23 #include <sys/signalvar.h> 24 25 #include <machine/apmvar.h> 26 #include <machine/bus.h> 27 #include <machine/fdt.h> 28 29 #include <dev/clock_subr.h> 30 #include <dev/ofw/openfirm.h> 31 #include <dev/ofw/ofw_gpio.h> 32 #include <dev/ofw/ofw_misc.h> 33 #include <dev/ofw/fdt.h> 34 35 #include <arm64/dev/aplmbox.h> 36 #include <arm64/dev/rtkit.h> 37 38 #include "apm.h" 39 40 extern int lid_action; 41 extern void (*simplefb_burn_hook)(u_int); 42 43 extern void (*cpuresetfn)(void); 44 extern void (*powerdownfn)(void); 45 46 extern int (*hw_battery_setchargemode)(int); 47 extern int (*hw_battery_setchargestart)(int); 48 extern int (*hw_battery_setchargestop)(int); 49 extern int hw_battery_chargemode; 50 extern int hw_battery_chargestart; 51 extern int hw_battery_chargestop; 52 53 /* SMC mailbox endpoint */ 54 #define SMC_EP 32 55 56 /* SMC commands */ 57 #define SMC_CMD(d) ((d) & 0xff) 58 #define SMC_READ_KEY 0x10 59 #define SMC_WRITE_KEY 0x11 60 #define SMC_GET_KEY_BY_INDEX 0x12 61 #define SMC_GET_KEY_INFO 0x13 62 #define SMC_GET_SRAM_ADDR 0x17 63 #define SMC_SRAM_SIZE 0x4000 64 #define SMC_NOTIFICATION 0x18 65 66 /* SMC errors */ 67 #define SMC_ERROR(d) ((d) & 0xff) 68 #define SMC_OK 0x00 69 #define SMC_KEYNOTFOUND 0x84 70 71 /* SMC keys */ 72 #define SMC_KEY(s) ((s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3]) 73 74 struct smc_key_info { 75 uint8_t size; 76 uint8_t type[4]; 77 uint8_t flags; 78 }; 79 80 /* SMC GPIO commands */ 81 #define SMC_GPIO_CMD_OUTPUT (0x01 << 24) 82 83 /* RTC related constants */ 84 #define RTC_OFFSET_LEN 6 85 #define SMC_CLKM_LEN 6 86 87 struct aplsmc_sensor { 88 const char *key; 89 const char *key_type; 90 enum sensor_type type; 91 int scale; 92 const char *desc; 93 int flags; 94 }; 95 96 /* SMC events */ 97 #define SMC_EV_TYPE(d) (((d) >> 48) & 0xffff) 98 #define SMC_EV_TYPE_BTN 0x7201 99 #define SMC_EV_TYPE_LID 0x7203 100 #define SMC_EV_SUBTYPE(d) (((d) >> 40) & 0xff) 101 #define SMC_EV_DATA(d) (((d) >> 32) & 0xff) 102 103 /* Button events */ 104 #define SMC_PWRBTN_OFF 0x00 105 #define SMC_PWRBTN_SHORT 0x01 106 #define SMC_PWRBTN_TOUCHID 0x06 107 #define SMC_PWRBTN_LONG 0xfe 108 109 /* Lid events */ 110 #define SMC_LID_OPEN 0x00 111 #define SMC_LID_CLOSE 0x01 112 113 #define APLSMC_BE (1 << 0) 114 #define APLSMC_HIDDEN (1 << 1) 115 116 #define APLSMC_MAX_SENSORS 19 117 118 struct aplsmc_softc { 119 struct device sc_dev; 120 bus_space_tag_t sc_iot; 121 bus_space_handle_t sc_ioh; 122 bus_space_handle_t sc_sram_ioh; 123 124 void *sc_ih; 125 126 struct rtkit_state *sc_rs; 127 uint8_t sc_msgid; 128 uint64_t sc_data; 129 130 struct gpio_controller sc_gc; 131 132 int sc_rtc_node; 133 struct todr_chip_handle sc_todr; 134 135 int sc_reboot_node; 136 137 struct aplsmc_sensor *sc_smcsensors[APLSMC_MAX_SENSORS]; 138 struct ksensor sc_sensors[APLSMC_MAX_SENSORS]; 139 int sc_nsensors; 140 struct ksensordev sc_sensordev; 141 uint32_t sc_suspend_pstr; 142 }; 143 144 #define CH0I_DISCHARGE (1 << 0) 145 #define CH0C_INHIBIT (1 << 0) 146 #define CHLS_FORCE_DISCHARGE (1 << 8) 147 148 struct aplsmc_softc *aplsmc_sc; 149 150 #ifndef SMALL_KERNEL 151 152 struct aplsmc_sensor aplsmc_sensors[] = { 153 { "ACDI", "ui16", SENSOR_INDICATOR, 1, "power supply" }, 154 { "B0RM", "ui16", SENSOR_AMPHOUR, 1000, "remaining battery capacity", 155 APLSMC_BE }, 156 { "B0FC", "ui16", SENSOR_AMPHOUR, 1000, "last full battery capacity" }, 157 { "B0DC", "ui16", SENSOR_AMPHOUR, 1000, "battery design capacity" }, 158 { "B0AV", "ui16", SENSOR_VOLTS_DC, 1000, "battery" }, 159 { "B0CT", "ui16", SENSOR_INTEGER, 1, "battery discharge cycles" }, 160 { "B0TF", "ui16", SENSOR_INTEGER, 1, "battery time-to-full", 161 APLSMC_HIDDEN }, 162 { "B0TE", "ui16", SENSOR_INTEGER, 1, "battery time-to-empty", 163 APLSMC_HIDDEN }, 164 { "F0Ac", "flt ", SENSOR_FANRPM, 1, "" }, 165 { "ID0R", "flt ", SENSOR_AMPS, 1000000, "input" }, 166 { "PDTR", "flt ", SENSOR_WATTS, 1000000, "input" }, 167 { "PSTR", "flt ", SENSOR_WATTS, 1000000, "system" }, 168 { "TB0T", "flt ", SENSOR_TEMP, 1000000, "battery" }, 169 { "TCHP", "flt ", SENSOR_TEMP, 1000000, "charger" }, 170 { "TW0P", "flt ", SENSOR_TEMP, 1000000, "wireless" }, 171 { "Ts0P", "flt ", SENSOR_TEMP, 1000000, "palm rest" }, 172 { "Ts1P", "flt ", SENSOR_TEMP, 1000000, "palm rest" }, 173 { "VD0R", "flt ", SENSOR_VOLTS_DC, 1000000, "input" }, 174 }; 175 176 #endif 177 178 int aplsmc_match(struct device *, void *, void *); 179 void aplsmc_attach(struct device *, struct device *, void *); 180 int aplsmc_activate(struct device *, int); 181 182 const struct cfattach aplsmc_ca = { 183 sizeof (struct aplsmc_softc), aplsmc_match, aplsmc_attach, 184 NULL, aplsmc_activate 185 }; 186 187 struct cfdriver aplsmc_cd = { 188 NULL, "aplsmc", DV_DULL 189 }; 190 191 void aplsmc_callback(void *, uint64_t); 192 int aplsmc_send_cmd(struct aplsmc_softc *, uint16_t, uint32_t, uint16_t); 193 int aplsmc_wait_cmd(struct aplsmc_softc *sc); 194 int aplsmc_read_key(struct aplsmc_softc *, uint32_t, void *, size_t); 195 int aplsmc_write_key(struct aplsmc_softc *, uint32_t, void *, size_t); 196 int64_t aplsmc_convert_flt(uint32_t, int); 197 void aplsmc_refresh_sensors(void *); 198 int aplsmc_apminfo(struct apm_power_info *); 199 void aplsmc_set_pin(void *, uint32_t *, int); 200 int aplsmc_gettime(struct todr_chip_handle *, struct timeval *); 201 int aplsmc_settime(struct todr_chip_handle *, struct timeval *); 202 void aplsmc_reset(void); 203 void aplsmc_powerdown(void); 204 void aplsmc_reboot_attachhook(struct device *); 205 void aplsmc_battery_init(struct aplsmc_softc *); 206 int aplsmc_battery_setchargemode(int); 207 int aplsmc_battery_setchargestart(int); 208 int aplsmc_battery_chls_setchargestop(int); 209 int aplsmc_battery_chwa_setchargestop(int); 210 211 int 212 aplsmc_match(struct device *parent, void *match, void *aux) 213 { 214 struct fdt_attach_args *faa = aux; 215 216 return OF_is_compatible(faa->fa_node, "apple,smc"); 217 } 218 219 void 220 aplsmc_attach(struct device *parent, struct device *self, void *aux) 221 { 222 struct aplsmc_softc *sc = (struct aplsmc_softc *)self; 223 struct fdt_attach_args *faa = aux; 224 uint8_t data[SMC_CLKM_LEN]; 225 uint8_t ntap; 226 int error, node; 227 #ifndef SMALL_KERNEL 228 int i; 229 #endif 230 231 if (faa->fa_nreg < 1) { 232 printf(": no registers\n"); 233 return; 234 } 235 236 sc->sc_iot = faa->fa_iot; 237 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 238 faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 239 printf(": can't map registers\n"); 240 return; 241 } 242 243 sc->sc_rs = rtkit_init(faa->fa_node, NULL, RK_WAKEUP, NULL); 244 if (sc->sc_rs == NULL) { 245 printf(": can't map mailbox channel\n"); 246 return; 247 } 248 249 error = rtkit_boot(sc->sc_rs); 250 if (error) { 251 printf(": can't boot firmware\n"); 252 return; 253 } 254 255 error = rtkit_start_endpoint(sc->sc_rs, SMC_EP, aplsmc_callback, sc); 256 if (error) { 257 printf(": can't start SMC endpoint\n"); 258 return; 259 } 260 261 aplsmc_send_cmd(sc, SMC_GET_SRAM_ADDR, 0, 0); 262 error = aplsmc_wait_cmd(sc); 263 if (error) { 264 printf(": can't get SRAM address\n"); 265 return; 266 } 267 268 if (bus_space_map(sc->sc_iot, sc->sc_data, 269 SMC_SRAM_SIZE, 0, &sc->sc_sram_ioh)) { 270 printf(": can't map SRAM\n"); 271 return; 272 } 273 274 printf("\n"); 275 276 aplsmc_sc = sc; 277 278 node = OF_getnodebyname(faa->fa_node, "gpio"); 279 if (node) { 280 sc->sc_gc.gc_node = node; 281 sc->sc_gc.gc_cookie = sc; 282 sc->sc_gc.gc_set_pin = aplsmc_set_pin; 283 gpio_controller_register(&sc->sc_gc); 284 } 285 286 /* 287 * Only provide TODR implementation if the "CLKM" key is 288 * supported by the SMC firmware. 289 */ 290 error = aplsmc_read_key(sc, SMC_KEY("CLKM"), &data, SMC_CLKM_LEN); 291 node = OF_getnodebyname(faa->fa_node, "rtc"); 292 if (node && error == 0) { 293 sc->sc_rtc_node = node; 294 sc->sc_todr.cookie = sc; 295 sc->sc_todr.todr_gettime = aplsmc_gettime; 296 sc->sc_todr.todr_settime = aplsmc_settime; 297 sc->sc_todr.todr_quality = 1000; 298 todr_attach(&sc->sc_todr); 299 } 300 301 node = OF_getnodebyname(faa->fa_node, "reboot"); 302 if (node) { 303 sc->sc_reboot_node = node; 304 cpuresetfn = aplsmc_reset; 305 powerdownfn = aplsmc_powerdown; 306 config_mountroot(self, aplsmc_reboot_attachhook); 307 } 308 309 /* Enable notifications. */ 310 ntap = 1; 311 aplsmc_write_key(sc, SMC_KEY("NTAP"), &ntap, sizeof(ntap)); 312 313 #ifndef SMALL_KERNEL 314 315 for (i = 0; i < nitems(aplsmc_sensors); i++) { 316 struct smc_key_info info; 317 318 aplsmc_send_cmd(sc, SMC_GET_KEY_INFO, 319 SMC_KEY(aplsmc_sensors[i].key), 0); 320 error = aplsmc_wait_cmd(sc); 321 if (error || SMC_ERROR(sc->sc_data) != SMC_OK) 322 continue; 323 324 bus_space_read_region_1(sc->sc_iot, sc->sc_sram_ioh, 0, 325 (uint8_t *)&info, sizeof(info)); 326 327 /* Skip if the key type doesn't match. */ 328 if (memcmp(aplsmc_sensors[i].key_type, info.type, 329 sizeof(info.type)) != 0) 330 continue; 331 332 if (sc->sc_nsensors >= APLSMC_MAX_SENSORS) { 333 printf("%s: maximum number of sensors exceeded\n", 334 sc->sc_dev.dv_xname); 335 break; 336 } 337 338 sc->sc_smcsensors[sc->sc_nsensors] = &aplsmc_sensors[i]; 339 strlcpy(sc->sc_sensors[sc->sc_nsensors].desc, 340 aplsmc_sensors[i].desc, sizeof(sc->sc_sensors[0].desc)); 341 sc->sc_sensors[sc->sc_nsensors].type = aplsmc_sensors[i].type; 342 if (!(aplsmc_sensors[i].flags & APLSMC_HIDDEN)) { 343 sensor_attach(&sc->sc_sensordev, 344 &sc->sc_sensors[sc->sc_nsensors]); 345 } 346 sc->sc_nsensors++; 347 } 348 349 aplsmc_refresh_sensors(sc); 350 351 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, 352 sizeof(sc->sc_sensordev.xname)); 353 sensordev_install(&sc->sc_sensordev); 354 sensor_task_register(sc, aplsmc_refresh_sensors, 5); 355 356 #if NAPM > 0 357 apm_setinfohook(aplsmc_apminfo); 358 #endif 359 360 aplsmc_battery_init(sc); 361 #endif 362 363 #ifdef SUSPEND 364 device_register_wakeup(&sc->sc_dev); 365 #endif 366 } 367 368 int 369 aplsmc_activate(struct device *self, int act) 370 { 371 #ifdef SUSPEND 372 struct aplsmc_softc *sc = (struct aplsmc_softc *)self; 373 int64_t value; 374 375 switch (act) { 376 case DVACT_WAKEUP: 377 value = aplsmc_convert_flt(sc->sc_suspend_pstr, 100); 378 printf("%s: system %lld.%02lld W\n", sc->sc_dev.dv_xname, 379 value / 100, value % 100); 380 } 381 #endif 382 383 return 0; 384 } 385 386 void 387 aplsmc_handle_notification(struct aplsmc_softc *sc, uint64_t data) 388 { 389 extern int allowpowerdown; 390 #ifdef SUSPEND 391 extern int cpu_suspended; 392 uint32_t flt = 0; 393 394 if (cpu_suspended) { 395 aplsmc_read_key(sc, 'PSTR', &flt, sizeof(flt)); 396 sc->sc_suspend_pstr = flt; 397 398 switch (SMC_EV_TYPE(data)) { 399 case SMC_EV_TYPE_BTN: 400 switch (SMC_EV_SUBTYPE(data)) { 401 case SMC_PWRBTN_SHORT: 402 case SMC_PWRBTN_TOUCHID: 403 cpu_suspended = 0; 404 break; 405 } 406 break; 407 case SMC_EV_TYPE_LID: 408 switch (SMC_EV_SUBTYPE(data)) { 409 case SMC_LID_OPEN: 410 cpu_suspended = 0; 411 break; 412 } 413 break; 414 } 415 416 return; 417 } 418 #endif 419 420 switch (SMC_EV_TYPE(data)) { 421 case SMC_EV_TYPE_BTN: 422 switch (SMC_EV_SUBTYPE(data)) { 423 case SMC_PWRBTN_SHORT: 424 case SMC_PWRBTN_TOUCHID: 425 if (SMC_EV_DATA(data) == 1) { 426 if (allowpowerdown) { 427 allowpowerdown = 0; 428 prsignal(initprocess, SIGUSR2); 429 } 430 } 431 break; 432 case SMC_PWRBTN_LONG: 433 break; 434 case SMC_PWRBTN_OFF: 435 /* XXX Do emergency shutdown? */ 436 break; 437 default: 438 printf("%s: SMV_EV_TYPE_BTN 0x%016llx\n", 439 sc->sc_dev.dv_xname, data); 440 break; 441 } 442 break; 443 case SMC_EV_TYPE_LID: 444 switch (lid_action) { 445 case 0: 446 switch (SMC_EV_SUBTYPE(data)) { 447 case SMC_LID_OPEN: 448 if (simplefb_burn_hook) 449 simplefb_burn_hook(1); 450 break; 451 case SMC_LID_CLOSE: 452 if (simplefb_burn_hook) 453 simplefb_burn_hook(0); 454 break; 455 default: 456 printf("%s: SMV_EV_TYPE_LID 0x%016llx\n", 457 sc->sc_dev.dv_xname, data); 458 break; 459 } 460 case 1: 461 #ifdef SUSPEND 462 request_sleep(SLEEP_SUSPEND); 463 #endif 464 break; 465 case 2: 466 /* XXX: hibernate */ 467 break; 468 } 469 break; 470 default: 471 #ifdef APLSMC_DEBUG 472 printf("%s: unhandled event 0x%016llx\n", 473 sc->sc_dev.dv_xname, data); 474 #endif 475 break; 476 } 477 } 478 479 void 480 aplsmc_callback(void *arg, uint64_t data) 481 { 482 struct aplsmc_softc *sc = arg; 483 484 if (SMC_CMD(data) == SMC_NOTIFICATION) { 485 aplsmc_handle_notification(sc, data); 486 return; 487 } 488 489 sc->sc_data = data; 490 wakeup(&sc->sc_data); 491 } 492 493 int 494 aplsmc_send_cmd(struct aplsmc_softc *sc, uint16_t cmd, uint32_t key, 495 uint16_t len) 496 { 497 uint64_t data; 498 499 data = cmd; 500 data |= (uint64_t)len << 16; 501 data |= (uint64_t)key << 32; 502 data |= (sc->sc_msgid++ & 0xf) << 12; 503 504 return rtkit_send_endpoint(sc->sc_rs, SMC_EP, data); 505 } 506 507 int 508 aplsmc_wait_cmd(struct aplsmc_softc *sc) 509 { 510 if (cold) { 511 int error, timo; 512 513 /* Poll for completion. */ 514 for (timo = 1000; timo > 0; timo--) { 515 error = rtkit_poll(sc->sc_rs); 516 if (error == 0) 517 return 0; 518 delay(10); 519 } 520 521 return EWOULDBLOCK; 522 } 523 524 /* Sleep until the callback wakes us up. */ 525 return tsleep_nsec(&sc->sc_data, PWAIT, "apsmc", 10000000); 526 } 527 528 int 529 aplsmc_read_key(struct aplsmc_softc *sc, uint32_t key, void *data, size_t len) 530 { 531 int error; 532 533 aplsmc_send_cmd(sc, SMC_READ_KEY, key, len); 534 error = aplsmc_wait_cmd(sc); 535 if (error) 536 return error; 537 switch (SMC_ERROR(sc->sc_data)) { 538 case SMC_OK: 539 break; 540 case SMC_KEYNOTFOUND: 541 return EINVAL; 542 break; 543 default: 544 return EIO; 545 break; 546 } 547 548 len = min(len, (sc->sc_data >> 16) & 0xffff); 549 if (len > sizeof(uint32_t)) { 550 bus_space_read_region_1(sc->sc_iot, sc->sc_sram_ioh, 0, 551 data, len); 552 } else { 553 uint32_t tmp = (sc->sc_data >> 32); 554 memcpy(data, &tmp, len); 555 } 556 557 return 0; 558 } 559 560 int 561 aplsmc_write_key(struct aplsmc_softc *sc, uint32_t key, void *data, size_t len) 562 { 563 bus_space_write_region_1(sc->sc_iot, sc->sc_sram_ioh, 0, data, len); 564 bus_space_barrier(sc->sc_iot, sc->sc_sram_ioh, 0, len, 565 BUS_SPACE_BARRIER_WRITE); 566 aplsmc_send_cmd(sc, SMC_WRITE_KEY, key, len); 567 return aplsmc_wait_cmd(sc); 568 } 569 570 #ifndef SMALL_KERNEL 571 572 int64_t 573 aplsmc_convert_flt(uint32_t flt, int scale) 574 { 575 int64_t mant; 576 int sign, exp; 577 578 /* 579 * Convert floating-point to integer, trying to keep as much 580 * resolution as possible given the scaling factor. 581 */ 582 sign = (flt >> 31) ? -1 : 1; 583 exp = ((flt >> 23) & 0xff) - 127; 584 mant = (flt & 0x7fffff) | 0x800000; 585 mant *= scale; 586 if (exp < 23) 587 return sign * (mant >> (23 - exp)); 588 else 589 return sign * (mant << (exp - 23)); 590 } 591 592 void 593 aplsmc_refresh_sensors(void *arg) 594 { 595 extern int hw_power; 596 struct aplsmc_softc *sc = arg; 597 struct aplsmc_sensor *sensor; 598 int64_t value; 599 uint32_t key; 600 int i, error; 601 602 for (i = 0; i < sc->sc_nsensors; i++) { 603 sensor = sc->sc_smcsensors[i]; 604 key = SMC_KEY(sensor->key); 605 606 if (strcmp(sensor->key_type, "ui8 ") == 0) { 607 uint8_t ui8; 608 609 error = aplsmc_read_key(sc, key, &ui8, sizeof(ui8)); 610 value = (int64_t)ui8 * sensor->scale; 611 } else if (strcmp(sensor->key_type, "ui16") == 0) { 612 uint16_t ui16; 613 614 error = aplsmc_read_key(sc, key, &ui16, sizeof(ui16)); 615 if (sensor->flags & APLSMC_BE) 616 ui16 = betoh16(ui16); 617 value = (int64_t)ui16 * sensor->scale; 618 } else if (strcmp(sensor->key_type, "flt ") == 0) { 619 uint32_t flt; 620 621 error = aplsmc_read_key(sc, key, &flt, sizeof(flt)); 622 if (sensor->flags & APLSMC_BE) 623 flt = betoh32(flt); 624 value = aplsmc_convert_flt(flt, sensor->scale); 625 } 626 627 /* Apple reports temperatures in degC. */ 628 if (sensor->type == SENSOR_TEMP) 629 value += 273150000; 630 631 if (error) { 632 sc->sc_sensors[i].flags |= SENSOR_FUNKNOWN; 633 } else { 634 sc->sc_sensors[i].flags &= ~SENSOR_FUNKNOWN; 635 sc->sc_sensors[i].value = value; 636 } 637 638 if (strcmp(sensor->key, "ACDI") == 0) 639 hw_power = (value > 0); 640 } 641 } 642 643 #if NAPM > 0 644 645 int 646 aplsmc_apminfo(struct apm_power_info *info) 647 { 648 struct aplsmc_sensor *sensor; 649 struct ksensor *ksensor; 650 struct aplsmc_softc *sc = aplsmc_sc; 651 int remaining = -1, capacity = -1, i; 652 653 info->battery_state = APM_BATT_UNKNOWN; 654 info->ac_state = APM_AC_UNKNOWN; 655 info->battery_life = 0; 656 info->minutes_left = -1; 657 658 for (i = 0; i < sc->sc_nsensors; i++) { 659 sensor = sc->sc_smcsensors[i]; 660 ksensor = &sc->sc_sensors[i]; 661 662 if (ksensor->flags & SENSOR_FUNKNOWN) 663 continue; 664 665 if (strcmp(sensor->key, "ACDI") == 0) { 666 info->ac_state = ksensor->value ? 667 APM_AC_ON : APM_AC_OFF; 668 } else if (strcmp(sensor->key, "B0RM") == 0) 669 remaining = ksensor->value; 670 else if (strcmp(sensor->key, "B0FC") == 0) 671 capacity = ksensor->value; 672 else if ((strcmp(sensor->key, "B0TE") == 0) && 673 (ksensor->value != 0xffff)) 674 info->minutes_left = ksensor->value; 675 else if ((strcmp(sensor->key, "B0TF") == 0) && 676 (ksensor->value != 0xffff)) { 677 info->battery_state = APM_BATT_CHARGING; 678 info->minutes_left = ksensor->value; 679 } 680 } 681 682 /* calculate remaining battery if we have sane values */ 683 if (remaining > -1 && capacity > 0) { 684 info->battery_life = ((remaining * 100) / capacity); 685 if (info->battery_state != APM_BATT_CHARGING) { 686 if (info->battery_life > 50) 687 info->battery_state = APM_BATT_HIGH; 688 else if (info->battery_life > 25) 689 info->battery_state = APM_BATT_LOW; 690 else 691 info->battery_state = APM_BATT_CRITICAL; 692 } 693 } 694 695 return 0; 696 } 697 698 #endif 699 #endif 700 701 void 702 aplsmc_set_pin(void *cookie, uint32_t *cells, int val) 703 { 704 struct aplsmc_softc *sc = cookie; 705 static char *digits = "0123456789abcdef"; 706 uint32_t pin = cells[0]; 707 uint32_t flags = cells[1]; 708 uint32_t key = SMC_KEY("gP\0\0"); 709 uint32_t data; 710 711 KASSERT(pin < 256); 712 713 key |= (digits[(pin >> 0) & 0xf] << 0); 714 key |= (digits[(pin >> 4) & 0xf] << 8); 715 716 if (flags & GPIO_ACTIVE_LOW) 717 val = !val; 718 data = SMC_GPIO_CMD_OUTPUT | !!val; 719 720 aplsmc_write_key(sc, key, &data, sizeof(data)); 721 } 722 723 int 724 aplsmc_gettime(struct todr_chip_handle *handle, struct timeval *tv) 725 { 726 struct aplsmc_softc *sc = handle->cookie; 727 uint8_t data[8] = {}; 728 uint64_t offset, time; 729 int error; 730 731 error = nvmem_read_cell(sc->sc_rtc_node, "rtc_offset", &data, 732 RTC_OFFSET_LEN); 733 if (error) 734 return error; 735 offset = lemtoh64(data); 736 737 error = aplsmc_read_key(sc, SMC_KEY("CLKM"), &data, SMC_CLKM_LEN); 738 if (error) 739 return error; 740 time = lemtoh64(data) + offset; 741 742 tv->tv_sec = (time >> 15); 743 tv->tv_usec = (((time & 0x7fff) * 1000000) >> 15); 744 return 0; 745 } 746 747 int 748 aplsmc_settime(struct todr_chip_handle *handle, struct timeval *tv) 749 { 750 struct aplsmc_softc *sc = handle->cookie; 751 uint8_t data[8] = {}; 752 uint64_t offset, time; 753 int error; 754 755 error = aplsmc_read_key(sc, SMC_KEY("CLKM"), &data, SMC_CLKM_LEN); 756 if (error) 757 return error; 758 759 time = ((uint64_t)tv->tv_sec << 15); 760 time |= ((uint64_t)tv->tv_usec << 15) / 1000000; 761 offset = time - lemtoh64(data); 762 763 htolem64(data, offset); 764 return nvmem_write_cell(sc->sc_rtc_node, "rtc_offset", &data, 765 RTC_OFFSET_LEN); 766 } 767 768 void 769 aplsmc_reboot_attachhook(struct device *self) 770 { 771 struct aplsmc_softc *sc = (struct aplsmc_softc *)self; 772 uint8_t count = 0; 773 774 /* Reset error counters. */ 775 nvmem_write_cell(sc->sc_reboot_node, "boot_error_count", 776 &count, sizeof(count)); 777 nvmem_write_cell(sc->sc_reboot_node, "panic_count", 778 &count, sizeof(count)); 779 } 780 781 void 782 aplsmc_reset(void) 783 { 784 struct aplsmc_softc *sc = aplsmc_sc; 785 uint32_t key = SMC_KEY("MBSE"); 786 uint32_t rest = SMC_KEY("rest"); 787 uint32_t phra = SMC_KEY("phra"); 788 uint8_t boot_stage = 0; 789 790 aplsmc_write_key(sc, key, &rest, sizeof(rest)); 791 nvmem_write_cell(sc->sc_reboot_node, "boot_stage", 792 &boot_stage, sizeof(boot_stage)); 793 aplsmc_write_key(sc, key, &phra, sizeof(phra)); 794 } 795 796 void 797 aplsmc_powerdown(void) 798 { 799 struct aplsmc_softc *sc = aplsmc_sc; 800 uint32_t key = SMC_KEY("MBSE"); 801 uint32_t offw = SMC_KEY("offw"); 802 uint32_t off1 = SMC_KEY("off1"); 803 uint8_t boot_stage = 0; 804 uint8_t shutdown_flag = 1; 805 806 aplsmc_write_key(sc, key, &offw, sizeof(offw)); 807 nvmem_write_cell(sc->sc_reboot_node, "boot_stage", 808 &boot_stage, sizeof(boot_stage)); 809 nvmem_write_cell(sc->sc_reboot_node, "shutdown_flag", 810 &shutdown_flag, sizeof(shutdown_flag)); 811 aplsmc_write_key(sc, key, &off1, sizeof(off1)); 812 } 813 814 #ifndef SMALL_KERNEL 815 816 void 817 aplsmc_battery_init(struct aplsmc_softc *sc) 818 { 819 uint8_t ch0i, ch0c, chwa; 820 int error, stop; 821 822 error = aplsmc_read_key(sc, SMC_KEY("CH0I"), &ch0i, sizeof(ch0i)); 823 if (error) 824 return; 825 error = aplsmc_read_key(sc, SMC_KEY("CH0C"), &ch0c, sizeof(ch0c)); 826 if (error) 827 return; 828 829 if (ch0i & CH0I_DISCHARGE) 830 hw_battery_chargemode = -1; 831 else if (ch0c & CH0C_INHIBIT) 832 hw_battery_chargemode = 0; 833 else 834 hw_battery_chargemode = 1; 835 836 hw_battery_setchargemode = aplsmc_battery_setchargemode; 837 838 /* 839 * The system firmware for macOS 15 (Sequoia) introduced a new 840 * CHLS key that allows setting the level at which to stop 841 * charging, and dropped support for the old CHWA key that 842 * only supports a fixed limit of 80%. However, CHLS is 843 * broken in some beta versions. Those versions still support 844 * CHWA so prefer that over CHLS. 845 */ 846 error = aplsmc_read_key(sc, SMC_KEY("CHWA"), &chwa, sizeof(chwa)); 847 if (error) { 848 uint16_t chls; 849 850 error = aplsmc_read_key(sc, SMC_KEY("CHLS"), 851 &chls, sizeof(chls)); 852 if (error) 853 return; 854 stop = (chls & 0xff) ? (chls & 0xff) : 100; 855 hw_battery_setchargestop = aplsmc_battery_chls_setchargestop; 856 } else { 857 stop = chwa ? 80 : 100; 858 hw_battery_setchargestop = aplsmc_battery_chwa_setchargestop; 859 } 860 861 hw_battery_setchargestart = aplsmc_battery_setchargestart; 862 863 hw_battery_chargestart = stop - 5; 864 hw_battery_chargestop = stop; 865 } 866 867 int 868 aplsmc_battery_setchargemode(int mode) 869 { 870 struct aplsmc_softc *sc = aplsmc_sc; 871 uint8_t val; 872 int error; 873 874 switch (mode) { 875 case -1: 876 val = 0; 877 error = aplsmc_write_key(sc, SMC_KEY("CH0C"), 878 &val, sizeof(val)); 879 if (error) 880 return error; 881 val = 1; 882 error = aplsmc_write_key(sc, SMC_KEY("CH0I"), 883 &val, sizeof(val)); 884 if (error) 885 return error; 886 break; 887 case 0: 888 val = 0; 889 error = aplsmc_write_key(sc, SMC_KEY("CH0I"), 890 &val, sizeof(val)); 891 if (error) 892 return error; 893 val = 1; 894 error = aplsmc_write_key(sc, SMC_KEY("CH0C"), 895 &val, sizeof(val)); 896 if (error) 897 return error; 898 break; 899 case 1: 900 val = 0; 901 error = aplsmc_write_key(sc, SMC_KEY("CH0I"), 902 &val, sizeof(val)); 903 if (error) 904 return error; 905 val = 0; 906 error = aplsmc_write_key(sc, SMC_KEY("CH0C"), 907 &val, sizeof(val)); 908 if (error) 909 return error; 910 break; 911 default: 912 return EINVAL; 913 } 914 915 hw_battery_chargemode = mode; 916 return 0; 917 } 918 919 int 920 aplsmc_battery_setchargestart(int start) 921 { 922 return EOPNOTSUPP; 923 } 924 925 int 926 aplsmc_battery_chls_setchargestop(int stop) 927 { 928 struct aplsmc_softc *sc = aplsmc_sc; 929 uint16_t chls; 930 int error; 931 932 if (stop < 10) 933 stop = 10; 934 935 /* 936 * Setting the CHLS_FORCE_DISCHARGE flags makes sure the 937 * battery is discharged until the configured charge level is 938 * reached when the limit is lowered. 939 */ 940 chls = (stop == 100 ? 0 : stop) | CHLS_FORCE_DISCHARGE; 941 error = aplsmc_write_key(sc, SMC_KEY("CHLS"), &chls, sizeof(chls)); 942 if (error) 943 return error; 944 945 hw_battery_chargestart = stop - 5; 946 hw_battery_chargestop = stop; 947 948 return 0; 949 } 950 951 int 952 aplsmc_battery_chwa_setchargestop(int stop) 953 { 954 struct aplsmc_softc *sc = aplsmc_sc; 955 uint8_t chwa; 956 int error; 957 958 if (stop <= 80) { 959 stop = 80; 960 chwa = 1; 961 } else { 962 stop = 100; 963 chwa = 0; 964 } 965 966 error = aplsmc_write_key(sc, SMC_KEY("CHWA"), &chwa, sizeof(chwa)); 967 if (error) 968 return error; 969 970 hw_battery_chargestart = stop - 5; 971 hw_battery_chargestop = stop; 972 973 return 0; 974 } 975 976 #endif 977