1 /* $OpenBSD: aplsmc.c,v 1.21 2023/01/09 20:29:35 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 /* SMC mailbox endpoint */ 47 #define SMC_EP 32 48 49 /* SMC commands */ 50 #define SMC_CMD(d) ((d) & 0xff) 51 #define SMC_READ_KEY 0x10 52 #define SMC_WRITE_KEY 0x11 53 #define SMC_GET_KEY_BY_INDEX 0x12 54 #define SMC_GET_KEY_INFO 0x13 55 #define SMC_GET_SRAM_ADDR 0x17 56 #define SMC_SRAM_SIZE 0x4000 57 #define SMC_NOTIFICATION 0x18 58 59 /* SMC errors */ 60 #define SMC_ERROR(d) ((d) & 0xff) 61 #define SMC_OK 0x00 62 #define SMC_KEYNOTFOUND 0x84 63 64 /* SMC keys */ 65 #define SMC_KEY(s) ((s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3]) 66 67 struct smc_key_info { 68 uint8_t size; 69 uint8_t type[4]; 70 uint8_t flags; 71 }; 72 73 /* SMC GPIO commands */ 74 #define SMC_GPIO_CMD_OUTPUT (0x01 << 24) 75 76 /* RTC related constants */ 77 #define RTC_OFFSET_LEN 6 78 #define SMC_CLKM_LEN 6 79 80 struct aplsmc_sensor { 81 const char *key; 82 const char *key_type; 83 enum sensor_type type; 84 int scale; 85 const char *desc; 86 int flags; 87 }; 88 89 /* SMC events */ 90 #define SMC_EV_TYPE(d) (((d) >> 48) & 0xffff) 91 #define SMC_EV_TYPE_BTN 0x7201 92 #define SMC_EV_TYPE_LID 0x7203 93 #define SMC_EV_SUBTYPE(d) (((d) >> 40) & 0xff) 94 #define SMC_EV_DATA(d) (((d) >> 32) & 0xff) 95 96 /* Button events */ 97 #define SMC_PWRBTN_OFF 0x00 98 #define SMC_PWRBTN_SHORT 0x01 99 #define SMC_PWRBTN_TOUCHID 0x06 100 #define SMC_PWRBTN_LONG 0xfe 101 102 /* Lid events */ 103 #define SMC_LID_OPEN 0x00 104 #define SMC_LID_CLOSE 0x01 105 106 #define APLSMC_BE (1 << 0) 107 #define APLSMC_HIDDEN (1 << 1) 108 109 #define APLSMC_MAX_SENSORS 19 110 111 struct aplsmc_softc { 112 struct device sc_dev; 113 bus_space_tag_t sc_iot; 114 bus_space_handle_t sc_ioh; 115 bus_space_handle_t sc_sram_ioh; 116 117 void *sc_ih; 118 119 struct rtkit_state *sc_rs; 120 uint8_t sc_msgid; 121 uint64_t sc_data; 122 123 struct gpio_controller sc_gc; 124 125 int sc_rtc_node; 126 struct todr_chip_handle sc_todr; 127 128 int sc_reboot_node; 129 130 struct aplsmc_sensor *sc_smcsensors[APLSMC_MAX_SENSORS]; 131 struct ksensor sc_sensors[APLSMC_MAX_SENSORS]; 132 int sc_nsensors; 133 struct ksensordev sc_sensordev; 134 }; 135 136 struct aplsmc_softc *aplsmc_sc; 137 138 #ifndef SMALL_KERNEL 139 140 struct aplsmc_sensor aplsmc_sensors[] = { 141 { "ACDI", "ui16", SENSOR_INDICATOR, 1, "power supply" }, 142 { "B0RM", "ui16", SENSOR_AMPHOUR, 1000, "remaining battery capacity", 143 APLSMC_BE }, 144 { "B0FC", "ui16", SENSOR_AMPHOUR, 1000, "last full battery capacity" }, 145 { "B0DC", "ui16", SENSOR_AMPHOUR, 1000, "battery design capacity" }, 146 { "B0AV", "ui16", SENSOR_VOLTS_DC, 1000, "battery" }, 147 { "B0CT", "ui16", SENSOR_INTEGER, 1, "battery discharge cycles" }, 148 { "B0TF", "ui16", SENSOR_INTEGER, 1, "battery time-to-full", 149 APLSMC_HIDDEN }, 150 { "B0TE", "ui16", SENSOR_INTEGER, 1, "battery time-to-empty", 151 APLSMC_HIDDEN }, 152 { "F0Ac", "flt ", SENSOR_FANRPM, 1, "" }, 153 { "ID0R", "flt ", SENSOR_AMPS, 1000000, "input" }, 154 { "PDTR", "flt ", SENSOR_WATTS, 1000000, "input" }, 155 { "PSTR", "flt ", SENSOR_WATTS, 1000000, "system" }, 156 { "TB0T", "flt ", SENSOR_TEMP, 1000000, "battery" }, 157 { "TCHP", "flt ", SENSOR_TEMP, 1000000, "charger" }, 158 { "TW0P", "flt ", SENSOR_TEMP, 1000000, "wireless" }, 159 { "Ts0P", "flt ", SENSOR_TEMP, 1000000, "palm rest" }, 160 { "Ts1P", "flt ", SENSOR_TEMP, 1000000, "palm rest" }, 161 { "VD0R", "flt ", SENSOR_VOLTS_DC, 1000000, "input" }, 162 }; 163 164 #endif 165 166 int aplsmc_match(struct device *, void *, void *); 167 void aplsmc_attach(struct device *, struct device *, void *); 168 169 const struct cfattach aplsmc_ca = { 170 sizeof (struct aplsmc_softc), aplsmc_match, aplsmc_attach 171 }; 172 173 struct cfdriver aplsmc_cd = { 174 NULL, "aplsmc", DV_DULL 175 }; 176 177 void aplsmc_callback(void *, uint64_t); 178 int aplsmc_send_cmd(struct aplsmc_softc *, uint16_t, uint32_t, uint16_t); 179 int aplsmc_wait_cmd(struct aplsmc_softc *sc); 180 int aplsmc_read_key(struct aplsmc_softc *, uint32_t, void *, size_t); 181 int aplsmc_write_key(struct aplsmc_softc *, uint32_t, void *, size_t); 182 void aplsmc_refresh_sensors(void *); 183 int aplsmc_apminfo(struct apm_power_info *); 184 void aplsmc_set_pin(void *, uint32_t *, int); 185 int aplsmc_gettime(struct todr_chip_handle *, struct timeval *); 186 int aplsmc_settime(struct todr_chip_handle *, struct timeval *); 187 void aplsmc_reset(void); 188 void aplsmc_powerdown(void); 189 void aplsmc_reboot_attachhook(struct device *); 190 191 int 192 aplsmc_match(struct device *parent, void *match, void *aux) 193 { 194 struct fdt_attach_args *faa = aux; 195 196 return OF_is_compatible(faa->fa_node, "apple,smc"); 197 } 198 199 void 200 aplsmc_attach(struct device *parent, struct device *self, void *aux) 201 { 202 struct aplsmc_softc *sc = (struct aplsmc_softc *)self; 203 struct fdt_attach_args *faa = aux; 204 uint8_t data[SMC_CLKM_LEN]; 205 uint8_t ntap; 206 int error, node; 207 #ifndef SMALL_KERNEL 208 int i; 209 #endif 210 211 if (faa->fa_nreg < 1) { 212 printf(": no registers\n"); 213 return; 214 } 215 216 sc->sc_iot = faa->fa_iot; 217 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 218 faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 219 printf(": can't map registers\n"); 220 return; 221 } 222 223 sc->sc_rs = rtkit_init(faa->fa_node, NULL, RK_WAKEUP, NULL); 224 if (sc->sc_rs == NULL) { 225 printf(": can't map mailbox channel\n"); 226 return; 227 } 228 229 error = rtkit_boot(sc->sc_rs); 230 if (error) { 231 printf(": can't boot firmware\n"); 232 return; 233 } 234 235 error = rtkit_start_endpoint(sc->sc_rs, SMC_EP, aplsmc_callback, sc); 236 if (error) { 237 printf(": can't start SMC endpoint\n"); 238 return; 239 } 240 241 aplsmc_send_cmd(sc, SMC_GET_SRAM_ADDR, 0, 0); 242 error = aplsmc_wait_cmd(sc); 243 if (error) { 244 printf(": can't get SRAM address\n"); 245 return; 246 } 247 248 if (bus_space_map(sc->sc_iot, sc->sc_data, 249 SMC_SRAM_SIZE, 0, &sc->sc_sram_ioh)) { 250 printf(": can't map SRAM\n"); 251 return; 252 } 253 254 printf("\n"); 255 256 aplsmc_sc = sc; 257 258 node = OF_getnodebyname(faa->fa_node, "gpio"); 259 if (node) { 260 sc->sc_gc.gc_node = node; 261 sc->sc_gc.gc_cookie = sc; 262 sc->sc_gc.gc_set_pin = aplsmc_set_pin; 263 gpio_controller_register(&sc->sc_gc); 264 } 265 266 /* 267 * Only provide TODR implementation if the "CLKM" key is 268 * supported by the SMC firmware. 269 */ 270 error = aplsmc_read_key(sc, SMC_KEY("CLKM"), &data, SMC_CLKM_LEN); 271 node = OF_getnodebyname(faa->fa_node, "rtc"); 272 if (node && error == 0) { 273 sc->sc_rtc_node = node; 274 sc->sc_todr.cookie = sc; 275 sc->sc_todr.todr_gettime = aplsmc_gettime; 276 sc->sc_todr.todr_settime = aplsmc_settime; 277 sc->sc_todr.todr_quality = 1000; 278 todr_attach(&sc->sc_todr); 279 } 280 281 node = OF_getnodebyname(faa->fa_node, "reboot"); 282 if (node) { 283 sc->sc_reboot_node = node; 284 cpuresetfn = aplsmc_reset; 285 powerdownfn = aplsmc_powerdown; 286 config_mountroot(self, aplsmc_reboot_attachhook); 287 } 288 289 /* Enable notifications. */ 290 ntap = 1; 291 aplsmc_write_key(sc, SMC_KEY("NTAP"), &ntap, sizeof(ntap)); 292 293 #ifndef SMALL_KERNEL 294 295 for (i = 0; i < nitems(aplsmc_sensors); i++) { 296 struct smc_key_info info; 297 298 aplsmc_send_cmd(sc, SMC_GET_KEY_INFO, 299 SMC_KEY(aplsmc_sensors[i].key), 0); 300 error = aplsmc_wait_cmd(sc); 301 if (error || SMC_ERROR(sc->sc_data) != SMC_OK) 302 continue; 303 304 bus_space_read_region_1(sc->sc_iot, sc->sc_sram_ioh, 0, 305 (uint8_t *)&info, sizeof(info)); 306 307 /* Skip if the key type doesn't match. */ 308 if (memcmp(aplsmc_sensors[i].key_type, info.type, 309 sizeof(info.type)) != 0) 310 continue; 311 312 if (sc->sc_nsensors >= APLSMC_MAX_SENSORS) { 313 printf("%s: maximum number of sensors exceeded\n", 314 sc->sc_dev.dv_xname); 315 break; 316 } 317 318 sc->sc_smcsensors[sc->sc_nsensors] = &aplsmc_sensors[i]; 319 strlcpy(sc->sc_sensors[sc->sc_nsensors].desc, 320 aplsmc_sensors[i].desc, sizeof(sc->sc_sensors[0].desc)); 321 sc->sc_sensors[sc->sc_nsensors].type = aplsmc_sensors[i].type; 322 if (!(aplsmc_sensors[i].flags & APLSMC_HIDDEN)) { 323 sensor_attach(&sc->sc_sensordev, 324 &sc->sc_sensors[sc->sc_nsensors]); 325 } 326 sc->sc_nsensors++; 327 } 328 329 aplsmc_refresh_sensors(sc); 330 331 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, 332 sizeof(sc->sc_sensordev.xname)); 333 sensordev_install(&sc->sc_sensordev); 334 sensor_task_register(sc, aplsmc_refresh_sensors, 5); 335 336 #if NAPM > 0 337 apm_setinfohook(aplsmc_apminfo); 338 #endif 339 340 #endif 341 342 #ifdef SUSPEND 343 device_register_wakeup(&sc->sc_dev); 344 #endif 345 } 346 347 void 348 aplsmc_handle_notification(struct aplsmc_softc *sc, uint64_t data) 349 { 350 extern int allowpowerdown; 351 #ifdef SUSPEND 352 extern int cpu_suspended; 353 extern void suspend(void); 354 355 if (cpu_suspended) { 356 switch (SMC_EV_TYPE(data)) { 357 case SMC_EV_TYPE_BTN: 358 switch (SMC_EV_SUBTYPE(data)) { 359 case SMC_PWRBTN_SHORT: 360 case SMC_PWRBTN_TOUCHID: 361 cpu_suspended = 0; 362 break; 363 } 364 break; 365 case SMC_EV_TYPE_LID: 366 switch (SMC_EV_SUBTYPE(data)) { 367 case SMC_LID_OPEN: 368 cpu_suspended = 0; 369 break; 370 } 371 break; 372 } 373 374 return; 375 } 376 #endif 377 378 switch (SMC_EV_TYPE(data)) { 379 case SMC_EV_TYPE_BTN: 380 switch (SMC_EV_SUBTYPE(data)) { 381 case SMC_PWRBTN_SHORT: 382 case SMC_PWRBTN_TOUCHID: 383 if (SMC_EV_DATA(data) == 1) { 384 if (allowpowerdown) { 385 allowpowerdown = 0; 386 prsignal(initprocess, SIGUSR2); 387 } 388 } 389 break; 390 case SMC_PWRBTN_LONG: 391 break; 392 case SMC_PWRBTN_OFF: 393 /* XXX Do emergency shutdown? */ 394 break; 395 default: 396 printf("%s: SMV_EV_TYPE_BTN 0x%016llx\n", 397 sc->sc_dev.dv_xname, data); 398 break; 399 } 400 break; 401 case SMC_EV_TYPE_LID: 402 switch (lid_action) { 403 case 0: 404 switch (SMC_EV_SUBTYPE(data)) { 405 case SMC_LID_OPEN: 406 if (simplefb_burn_hook) 407 simplefb_burn_hook(1); 408 break; 409 case SMC_LID_CLOSE: 410 if (simplefb_burn_hook) 411 simplefb_burn_hook(0); 412 break; 413 default: 414 printf("%s: SMV_EV_TYPE_LID 0x%016llx\n", 415 sc->sc_dev.dv_xname, data); 416 break; 417 } 418 case 1: 419 #ifdef SUSPEND 420 suspend(); 421 #endif 422 break; 423 case 2: 424 /* XXX: hibernate */ 425 break; 426 } 427 break; 428 default: 429 #ifdef APLSMC_DEBUG 430 printf("%s: unhandled event 0x%016llx\n", 431 sc->sc_dev.dv_xname, data); 432 #endif 433 break; 434 } 435 } 436 437 void 438 aplsmc_callback(void *arg, uint64_t data) 439 { 440 struct aplsmc_softc *sc = arg; 441 442 if (SMC_CMD(data) == SMC_NOTIFICATION) { 443 aplsmc_handle_notification(sc, data); 444 return; 445 } 446 447 sc->sc_data = data; 448 wakeup(&sc->sc_data); 449 } 450 451 int 452 aplsmc_send_cmd(struct aplsmc_softc *sc, uint16_t cmd, uint32_t key, 453 uint16_t len) 454 { 455 uint64_t data; 456 457 data = cmd; 458 data |= (uint64_t)len << 16; 459 data |= (uint64_t)key << 32; 460 data |= (sc->sc_msgid++ & 0xf) << 12; 461 462 return rtkit_send_endpoint(sc->sc_rs, SMC_EP, data); 463 } 464 465 int 466 aplsmc_wait_cmd(struct aplsmc_softc *sc) 467 { 468 if (cold) { 469 int error, timo; 470 471 /* Poll for completion. */ 472 for (timo = 1000; timo > 0; timo--) { 473 error = rtkit_poll(sc->sc_rs); 474 if (error == 0) 475 return 0; 476 delay(10); 477 } 478 479 return EWOULDBLOCK; 480 } 481 482 /* Sleep until the callback wakes us up. */ 483 return tsleep_nsec(&sc->sc_data, PWAIT, "apsmc", 10000000); 484 } 485 486 int 487 aplsmc_read_key(struct aplsmc_softc *sc, uint32_t key, void *data, size_t len) 488 { 489 int error; 490 491 aplsmc_send_cmd(sc, SMC_READ_KEY, key, len); 492 error = aplsmc_wait_cmd(sc); 493 if (error) 494 return error; 495 switch (SMC_ERROR(sc->sc_data)) { 496 case SMC_OK: 497 break; 498 case SMC_KEYNOTFOUND: 499 return EINVAL; 500 break; 501 default: 502 return EIO; 503 break; 504 } 505 506 len = min(len, (sc->sc_data >> 16) & 0xffff); 507 if (len > sizeof(uint32_t)) { 508 bus_space_read_region_1(sc->sc_iot, sc->sc_sram_ioh, 0, 509 data, len); 510 } else { 511 uint32_t tmp = (sc->sc_data >> 32); 512 memcpy(data, &tmp, len); 513 } 514 515 return 0; 516 } 517 518 int 519 aplsmc_write_key(struct aplsmc_softc *sc, uint32_t key, void *data, size_t len) 520 { 521 bus_space_write_region_1(sc->sc_iot, sc->sc_sram_ioh, 0, data, len); 522 bus_space_barrier(sc->sc_iot, sc->sc_sram_ioh, 0, len, 523 BUS_SPACE_BARRIER_WRITE); 524 aplsmc_send_cmd(sc, SMC_WRITE_KEY, key, len); 525 return aplsmc_wait_cmd(sc); 526 } 527 528 #ifndef SMALL_KERNEL 529 530 void 531 aplsmc_refresh_sensors(void *arg) 532 { 533 extern int hw_power; 534 struct aplsmc_softc *sc = arg; 535 struct aplsmc_sensor *sensor; 536 int64_t value; 537 uint32_t key; 538 int i, error; 539 540 for (i = 0; i < sc->sc_nsensors; i++) { 541 sensor = sc->sc_smcsensors[i]; 542 key = SMC_KEY(sensor->key); 543 544 if (strcmp(sensor->key_type, "ui8 ") == 0) { 545 uint8_t ui8; 546 547 error = aplsmc_read_key(sc, key, &ui8, sizeof(ui8)); 548 value = (int64_t)ui8 * sensor->scale; 549 } else if (strcmp(sensor->key_type, "ui16") == 0) { 550 uint16_t ui16; 551 552 error = aplsmc_read_key(sc, key, &ui16, sizeof(ui16)); 553 if (sensor->flags & APLSMC_BE) 554 ui16 = betoh16(ui16); 555 value = (int64_t)ui16 * sensor->scale; 556 } else if (strcmp(sensor->key_type, "flt ") == 0) { 557 uint32_t flt; 558 int64_t mant; 559 int sign, exp; 560 561 error = aplsmc_read_key(sc, key, &flt, sizeof(flt)); 562 if (sensor->flags & APLSMC_BE) 563 flt = betoh32(flt); 564 565 /* 566 * Convert floating-point to integer, trying 567 * to keep as much resolution as possible 568 * given the scaling factor for this sensor. 569 */ 570 sign = (flt >> 31) ? -1 : 1; 571 exp = ((flt >> 23) & 0xff) - 127; 572 mant = (flt & 0x7fffff) | 0x800000; 573 mant *= sensor->scale; 574 if (exp < 23) 575 value = sign * (mant >> (23 - exp)); 576 else 577 value = sign * (mant << (exp - 23)); 578 } 579 580 /* Apple reports temperatures in degC. */ 581 if (sensor->type == SENSOR_TEMP) 582 value += 273150000; 583 584 if (error) { 585 sc->sc_sensors[i].flags |= SENSOR_FUNKNOWN; 586 } else { 587 sc->sc_sensors[i].flags &= ~SENSOR_FUNKNOWN; 588 sc->sc_sensors[i].value = value; 589 } 590 591 if (strcmp(sensor->key, "ACDI") == 0) 592 hw_power = (value > 0); 593 } 594 } 595 596 #if NAPM > 0 597 598 int 599 aplsmc_apminfo(struct apm_power_info *info) 600 { 601 struct aplsmc_sensor *sensor; 602 struct ksensor *ksensor; 603 struct aplsmc_softc *sc = aplsmc_sc; 604 int remaining = -1, capacity = -1, i; 605 606 info->battery_state = APM_BATT_UNKNOWN; 607 info->ac_state = APM_AC_UNKNOWN; 608 info->battery_life = 0; 609 info->minutes_left = -1; 610 611 for (i = 0; i < sc->sc_nsensors; i++) { 612 sensor = sc->sc_smcsensors[i]; 613 ksensor = &sc->sc_sensors[i]; 614 615 if (ksensor->flags & SENSOR_FUNKNOWN) 616 continue; 617 618 if (strcmp(sensor->key, "ACDI") == 0) { 619 info->ac_state = ksensor->value ? 620 APM_AC_ON : APM_AC_OFF; 621 } else if (strcmp(sensor->key, "B0RM") == 0) 622 remaining = ksensor->value; 623 else if (strcmp(sensor->key, "B0FC") == 0) 624 capacity = ksensor->value; 625 else if ((strcmp(sensor->key, "B0TE") == 0) && 626 (ksensor->value != 0xffff)) 627 info->minutes_left = ksensor->value; 628 else if ((strcmp(sensor->key, "B0TF") == 0) && 629 (ksensor->value != 0xffff)) { 630 info->battery_state = APM_BATT_CHARGING; 631 info->minutes_left = ksensor->value; 632 } 633 } 634 635 /* calculate remaining battery if we have sane values */ 636 if (remaining > -1 && capacity > 0) { 637 info->battery_life = ((remaining * 100) / capacity); 638 if (info->battery_state != APM_BATT_CHARGING) { 639 if (info->battery_life > 50) 640 info->battery_state = APM_BATT_HIGH; 641 else if (info->battery_life > 25) 642 info->battery_state = APM_BATT_LOW; 643 else 644 info->battery_state = APM_BATT_CRITICAL; 645 } 646 } 647 648 return 0; 649 } 650 651 #endif 652 #endif 653 654 void 655 aplsmc_set_pin(void *cookie, uint32_t *cells, int val) 656 { 657 struct aplsmc_softc *sc = cookie; 658 static char *digits = "0123456789abcdef"; 659 uint32_t pin = cells[0]; 660 uint32_t flags = cells[1]; 661 uint32_t key = SMC_KEY("gP\0\0"); 662 uint32_t data; 663 664 KASSERT(pin < 256); 665 666 key |= (digits[(pin >> 0) & 0xf] << 0); 667 key |= (digits[(pin >> 4) & 0xf] << 8); 668 669 if (flags & GPIO_ACTIVE_LOW) 670 val = !val; 671 data = SMC_GPIO_CMD_OUTPUT | !!val; 672 673 aplsmc_write_key(sc, key, &data, sizeof(data)); 674 } 675 676 int 677 aplsmc_gettime(struct todr_chip_handle *handle, struct timeval *tv) 678 { 679 struct aplsmc_softc *sc = handle->cookie; 680 uint8_t data[8] = {}; 681 uint64_t offset, time; 682 int error; 683 684 error = nvmem_read_cell(sc->sc_rtc_node, "rtc_offset", &data, 685 RTC_OFFSET_LEN); 686 if (error) 687 return error; 688 offset = lemtoh64(data); 689 690 error = aplsmc_read_key(sc, SMC_KEY("CLKM"), &data, SMC_CLKM_LEN); 691 if (error) 692 return error; 693 time = lemtoh64(data) + offset; 694 695 tv->tv_sec = (time >> 15); 696 tv->tv_usec = (((time & 0x7fff) * 1000000) >> 15); 697 return 0; 698 } 699 700 int 701 aplsmc_settime(struct todr_chip_handle *handle, struct timeval *tv) 702 { 703 struct aplsmc_softc *sc = handle->cookie; 704 uint8_t data[8] = {}; 705 uint64_t offset, time; 706 int error; 707 708 error = aplsmc_read_key(sc, SMC_KEY("CLKM"), &data, SMC_CLKM_LEN); 709 if (error) 710 return error; 711 712 time = ((uint64_t)tv->tv_sec << 15); 713 time |= ((uint64_t)tv->tv_usec << 15) / 1000000; 714 offset = time - lemtoh64(data); 715 716 htolem64(data, offset); 717 return nvmem_write_cell(sc->sc_rtc_node, "rtc_offset", &data, 718 RTC_OFFSET_LEN); 719 } 720 721 void 722 aplsmc_reboot_attachhook(struct device *self) 723 { 724 struct aplsmc_softc *sc = (struct aplsmc_softc *)self; 725 uint8_t count = 0; 726 727 /* Reset error counters. */ 728 nvmem_write_cell(sc->sc_reboot_node, "boot_error_count", 729 &count, sizeof(count)); 730 nvmem_write_cell(sc->sc_reboot_node, "panic_count", 731 &count, sizeof(count)); 732 } 733 734 void 735 aplsmc_reset(void) 736 { 737 struct aplsmc_softc *sc = aplsmc_sc; 738 uint32_t key = SMC_KEY("MBSE"); 739 uint32_t rest = SMC_KEY("rest"); 740 uint32_t phra = SMC_KEY("phra"); 741 uint8_t boot_stage = 0; 742 743 aplsmc_write_key(sc, key, &rest, sizeof(rest)); 744 nvmem_write_cell(sc->sc_reboot_node, "boot_stage", 745 &boot_stage, sizeof(boot_stage)); 746 aplsmc_write_key(sc, key, &phra, sizeof(phra)); 747 } 748 749 void 750 aplsmc_powerdown(void) 751 { 752 struct aplsmc_softc *sc = aplsmc_sc; 753 uint32_t key = SMC_KEY("MBSE"); 754 uint32_t offw = SMC_KEY("offw"); 755 uint32_t off1 = SMC_KEY("off1"); 756 uint8_t boot_stage = 0; 757 uint8_t shutdown_flag = 1; 758 759 aplsmc_write_key(sc, key, &offw, sizeof(offw)); 760 nvmem_write_cell(sc->sc_reboot_node, "boot_stage", 761 &boot_stage, sizeof(boot_stage)); 762 nvmem_write_cell(sc->sc_reboot_node, "shutdown_flag", 763 &shutdown_flag, sizeof(shutdown_flag)); 764 aplsmc_write_key(sc, key, &off1, sizeof(off1)); 765 } 766