1 /*- 2 * Copyright (c) 2009 Nathan Whitehorn 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 19 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 21 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 */ 27 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 #include <sys/param.h> 32 #include <sys/bus.h> 33 #include <sys/systm.h> 34 #include <sys/module.h> 35 #include <sys/conf.h> 36 #include <sys/cpu.h> 37 #include <sys/clock.h> 38 #include <sys/ctype.h> 39 #include <sys/kernel.h> 40 #include <sys/kthread.h> 41 #include <sys/reboot.h> 42 #include <sys/rman.h> 43 #include <sys/sysctl.h> 44 #include <sys/unistd.h> 45 46 #include <machine/bus.h> 47 #include <machine/intr_machdep.h> 48 #include <machine/md_var.h> 49 50 #include <dev/iicbus/iicbus.h> 51 #include <dev/iicbus/iiconf.h> 52 #include <dev/led/led.h> 53 #include <dev/ofw/openfirm.h> 54 #include <dev/ofw/ofw_bus.h> 55 #include <dev/ofw/ofw_bus_subr.h> 56 #include <powerpc/powermac/macgpiovar.h> 57 58 #include "clock_if.h" 59 #include "iicbus_if.h" 60 61 struct smu_cmd { 62 volatile uint8_t cmd; 63 uint8_t len; 64 uint8_t data[254]; 65 66 STAILQ_ENTRY(smu_cmd) cmd_q; 67 }; 68 69 STAILQ_HEAD(smu_cmdq, smu_cmd); 70 71 struct smu_fan { 72 cell_t reg; 73 cell_t min_rpm; 74 cell_t max_rpm; 75 cell_t unmanaged_rpm; 76 char location[32]; 77 78 int old_style; 79 int setpoint; 80 }; 81 82 struct smu_sensor { 83 cell_t reg; 84 char location[32]; 85 enum { 86 SMU_CURRENT_SENSOR, 87 SMU_VOLTAGE_SENSOR, 88 SMU_POWER_SENSOR, 89 SMU_TEMP_SENSOR 90 } type; 91 }; 92 93 struct smu_softc { 94 device_t sc_dev; 95 struct mtx sc_mtx; 96 97 struct resource *sc_memr; 98 int sc_memrid; 99 int sc_u3; 100 101 bus_dma_tag_t sc_dmatag; 102 bus_space_tag_t sc_bt; 103 bus_space_handle_t sc_mailbox; 104 105 struct smu_cmd *sc_cmd, *sc_cur_cmd; 106 bus_addr_t sc_cmd_phys; 107 bus_dmamap_t sc_cmd_dmamap; 108 struct smu_cmdq sc_cmdq; 109 110 struct smu_fan *sc_fans; 111 int sc_nfans; 112 struct smu_sensor *sc_sensors; 113 int sc_nsensors; 114 115 int sc_doorbellirqid; 116 struct resource *sc_doorbellirq; 117 void *sc_doorbellirqcookie; 118 119 struct proc *sc_fanmgt_proc; 120 time_t sc_lastuserchange; 121 122 /* Calibration data */ 123 uint16_t sc_cpu_diode_scale; 124 int16_t sc_cpu_diode_offset; 125 126 uint16_t sc_cpu_volt_scale; 127 int16_t sc_cpu_volt_offset; 128 uint16_t sc_cpu_curr_scale; 129 int16_t sc_cpu_curr_offset; 130 131 uint16_t sc_slots_pow_scale; 132 int16_t sc_slots_pow_offset; 133 134 /* Thermal management parameters */ 135 int sc_target_temp; /* Default 55 C */ 136 int sc_critical_temp; /* Default 90 C */ 137 138 struct cdev *sc_leddev; 139 }; 140 141 /* regular bus attachment functions */ 142 143 static int smu_probe(device_t); 144 static int smu_attach(device_t); 145 static const struct ofw_bus_devinfo * 146 smu_get_devinfo(device_t bus, device_t dev); 147 148 /* cpufreq notification hooks */ 149 150 static void smu_cpufreq_pre_change(device_t, const struct cf_level *level); 151 static void smu_cpufreq_post_change(device_t, const struct cf_level *level); 152 153 /* clock interface */ 154 static int smu_gettime(device_t dev, struct timespec *ts); 155 static int smu_settime(device_t dev, struct timespec *ts); 156 157 /* utility functions */ 158 static int smu_run_cmd(device_t dev, struct smu_cmd *cmd, int wait); 159 static int smu_get_datablock(device_t dev, int8_t id, uint8_t *buf, 160 size_t len); 161 static void smu_attach_i2c(device_t dev, phandle_t i2croot); 162 static void smu_attach_fans(device_t dev, phandle_t fanroot); 163 static void smu_attach_sensors(device_t dev, phandle_t sensroot); 164 static void smu_fan_management_proc(void *xdev); 165 static void smu_manage_fans(device_t smu); 166 static void smu_set_sleepled(void *xdev, int onoff); 167 static int smu_server_mode(SYSCTL_HANDLER_ARGS); 168 static void smu_doorbell_intr(void *xdev); 169 static void smu_shutdown(void *xdev, int howto); 170 171 /* where to find the doorbell GPIO */ 172 173 static device_t smu_doorbell = NULL; 174 175 static device_method_t smu_methods[] = { 176 /* Device interface */ 177 DEVMETHOD(device_probe, smu_probe), 178 DEVMETHOD(device_attach, smu_attach), 179 180 /* Clock interface */ 181 DEVMETHOD(clock_gettime, smu_gettime), 182 DEVMETHOD(clock_settime, smu_settime), 183 184 /* ofw_bus interface */ 185 DEVMETHOD(bus_child_pnpinfo_str,ofw_bus_gen_child_pnpinfo_str), 186 DEVMETHOD(ofw_bus_get_devinfo, smu_get_devinfo), 187 DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 188 DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 189 DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 190 DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 191 DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 192 193 { 0, 0 }, 194 }; 195 196 static driver_t smu_driver = { 197 "smu", 198 smu_methods, 199 sizeof(struct smu_softc) 200 }; 201 202 static devclass_t smu_devclass; 203 204 DRIVER_MODULE(smu, nexus, smu_driver, smu_devclass, 0, 0); 205 MALLOC_DEFINE(M_SMU, "smu", "SMU Sensor Information"); 206 207 #define SMU_MAILBOX 0x8000860c 208 #define SMU_FANMGT_INTERVAL 1000 /* ms */ 209 210 /* Command types */ 211 #define SMU_ADC 0xd8 212 #define SMU_FAN 0x4a 213 #define SMU_I2C 0x9a 214 #define SMU_I2C_SIMPLE 0x00 215 #define SMU_I2C_NORMAL 0x01 216 #define SMU_I2C_COMBINED 0x02 217 #define SMU_MISC 0xee 218 #define SMU_MISC_GET_DATA 0x02 219 #define SMU_MISC_LED_CTRL 0x04 220 #define SMU_POWER 0xaa 221 #define SMU_POWER_EVENTS 0x8f 222 #define SMU_PWR_GET_POWERUP 0x00 223 #define SMU_PWR_SET_POWERUP 0x01 224 #define SMU_PWR_CLR_POWERUP 0x02 225 #define SMU_RTC 0x8e 226 #define SMU_RTC_GET 0x81 227 #define SMU_RTC_SET 0x80 228 229 /* Power event types */ 230 #define SMU_WAKEUP_KEYPRESS 0x01 231 #define SMU_WAKEUP_AC_INSERT 0x02 232 #define SMU_WAKEUP_AC_CHANGE 0x04 233 #define SMU_WAKEUP_RING 0x10 234 235 /* Data blocks */ 236 #define SMU_CPUTEMP_CAL 0x18 237 #define SMU_CPUVOLT_CAL 0x21 238 #define SMU_SLOTPW_CAL 0x78 239 240 /* Partitions */ 241 #define SMU_PARTITION 0x3e 242 #define SMU_PARTITION_LATEST 0x01 243 #define SMU_PARTITION_BASE 0x02 244 #define SMU_PARTITION_UPDATE 0x03 245 246 static int 247 smu_probe(device_t dev) 248 { 249 const char *name = ofw_bus_get_name(dev); 250 251 if (strcmp(name, "smu") != 0) 252 return (ENXIO); 253 254 device_set_desc(dev, "Apple System Management Unit"); 255 return (0); 256 } 257 258 static void 259 smu_phys_callback(void *xsc, bus_dma_segment_t *segs, int nsegs, int error) 260 { 261 struct smu_softc *sc = xsc; 262 263 sc->sc_cmd_phys = segs[0].ds_addr; 264 } 265 266 static int 267 smu_attach(device_t dev) 268 { 269 struct smu_softc *sc; 270 phandle_t node, child; 271 uint8_t data[12]; 272 273 sc = device_get_softc(dev); 274 275 mtx_init(&sc->sc_mtx, "smu", NULL, MTX_DEF); 276 sc->sc_cur_cmd = NULL; 277 sc->sc_doorbellirqid = -1; 278 279 sc->sc_u3 = 0; 280 if (OF_finddevice("/u3") != -1) 281 sc->sc_u3 = 1; 282 283 /* 284 * Map the mailbox area. This should be determined from firmware, 285 * but I have not found a simple way to do that. 286 */ 287 bus_dma_tag_create(NULL, 16, 0, BUS_SPACE_MAXADDR_32BIT, 288 BUS_SPACE_MAXADDR, NULL, NULL, PAGE_SIZE, 1, PAGE_SIZE, 0, NULL, 289 NULL, &(sc->sc_dmatag)); 290 sc->sc_bt = &bs_le_tag; 291 bus_space_map(sc->sc_bt, SMU_MAILBOX, 4, 0, &sc->sc_mailbox); 292 293 /* 294 * Allocate the command buffer. This can be anywhere in the low 4 GB 295 * of memory. 296 */ 297 bus_dmamem_alloc(sc->sc_dmatag, (void **)&sc->sc_cmd, BUS_DMA_WAITOK | 298 BUS_DMA_ZERO, &sc->sc_cmd_dmamap); 299 bus_dmamap_load(sc->sc_dmatag, sc->sc_cmd_dmamap, 300 sc->sc_cmd, PAGE_SIZE, smu_phys_callback, sc, 0); 301 STAILQ_INIT(&sc->sc_cmdq); 302 303 /* 304 * Set up handlers to change CPU voltage when CPU frequency is changed. 305 */ 306 EVENTHANDLER_REGISTER(cpufreq_pre_change, smu_cpufreq_pre_change, dev, 307 EVENTHANDLER_PRI_ANY); 308 EVENTHANDLER_REGISTER(cpufreq_post_change, smu_cpufreq_post_change, dev, 309 EVENTHANDLER_PRI_ANY); 310 311 /* 312 * Detect and attach child devices. 313 */ 314 node = ofw_bus_get_node(dev); 315 for (child = OF_child(node); child != 0; child = OF_peer(child)) { 316 char name[32]; 317 memset(name, 0, sizeof(name)); 318 OF_getprop(child, "name", name, sizeof(name)); 319 320 if (strncmp(name, "rpm-fans", 9) == 0 || 321 strncmp(name, "fans", 5) == 0) 322 smu_attach_fans(dev, child); 323 324 if (strncmp(name, "sensors", 8) == 0) 325 smu_attach_sensors(dev, child); 326 327 if (strncmp(name, "smu-i2c-control", 15) == 0) 328 smu_attach_i2c(dev, child); 329 } 330 331 /* Some SMUs have the I2C children directly under the bus. */ 332 smu_attach_i2c(dev, node); 333 334 /* 335 * Collect calibration constants. 336 */ 337 smu_get_datablock(dev, SMU_CPUTEMP_CAL, data, sizeof(data)); 338 sc->sc_cpu_diode_scale = (data[4] << 8) + data[5]; 339 sc->sc_cpu_diode_offset = (data[6] << 8) + data[7]; 340 341 smu_get_datablock(dev, SMU_CPUVOLT_CAL, data, sizeof(data)); 342 sc->sc_cpu_volt_scale = (data[4] << 8) + data[5]; 343 sc->sc_cpu_volt_offset = (data[6] << 8) + data[7]; 344 sc->sc_cpu_curr_scale = (data[8] << 8) + data[9]; 345 sc->sc_cpu_curr_offset = (data[10] << 8) + data[11]; 346 347 smu_get_datablock(dev, SMU_SLOTPW_CAL, data, sizeof(data)); 348 sc->sc_slots_pow_scale = (data[4] << 8) + data[5]; 349 sc->sc_slots_pow_offset = (data[6] << 8) + data[7]; 350 351 /* 352 * Set up simple-minded thermal management. 353 */ 354 sc->sc_target_temp = 55; 355 sc->sc_critical_temp = 90; 356 357 SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 358 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 359 "target_temp", CTLTYPE_INT | CTLFLAG_RW, &sc->sc_target_temp, 360 sizeof(int), "Target temperature (C)"); 361 SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 362 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 363 "critical_temp", CTLTYPE_INT | CTLFLAG_RW, 364 &sc->sc_critical_temp, sizeof(int), "Critical temperature (C)"); 365 366 kproc_create(smu_fan_management_proc, dev, &sc->sc_fanmgt_proc, 367 RFHIGHPID, 0, "smu_thermal"); 368 369 /* 370 * Set up LED interface 371 */ 372 sc->sc_leddev = led_create(smu_set_sleepled, dev, "sleepled"); 373 374 /* 375 * Reset on power loss behavior 376 */ 377 378 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 379 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 380 "server_mode", CTLTYPE_INT | CTLFLAG_RW, dev, 0, 381 smu_server_mode, "I", "Enable reboot after power failure"); 382 383 /* 384 * Set up doorbell interrupt. 385 */ 386 sc->sc_doorbellirqid = 0; 387 sc->sc_doorbellirq = bus_alloc_resource_any(smu_doorbell, SYS_RES_IRQ, 388 &sc->sc_doorbellirqid, RF_ACTIVE); 389 bus_setup_intr(smu_doorbell, sc->sc_doorbellirq, 390 INTR_TYPE_MISC | INTR_MPSAFE, NULL, smu_doorbell_intr, dev, 391 &sc->sc_doorbellirqcookie); 392 powerpc_config_intr(rman_get_start(sc->sc_doorbellirq), 393 INTR_TRIGGER_EDGE, INTR_POLARITY_LOW); 394 395 /* 396 * Connect RTC interface. 397 */ 398 clock_register(dev, 1000); 399 400 /* 401 * Learn about shutdown events 402 */ 403 EVENTHANDLER_REGISTER(shutdown_final, smu_shutdown, dev, 404 SHUTDOWN_PRI_LAST); 405 406 return (bus_generic_attach(dev)); 407 } 408 409 static const struct ofw_bus_devinfo * 410 smu_get_devinfo(device_t bus, device_t dev) 411 { 412 413 return (device_get_ivars(dev)); 414 } 415 416 static void 417 smu_send_cmd(device_t dev, struct smu_cmd *cmd) 418 { 419 struct smu_softc *sc; 420 421 sc = device_get_softc(dev); 422 423 mtx_assert(&sc->sc_mtx, MA_OWNED); 424 425 if (sc->sc_u3) 426 powerpc_pow_enabled = 0; /* SMU cannot work if we go to NAP */ 427 428 sc->sc_cur_cmd = cmd; 429 430 /* Copy the command to the mailbox */ 431 sc->sc_cmd->cmd = cmd->cmd; 432 sc->sc_cmd->len = cmd->len; 433 memcpy(sc->sc_cmd->data, cmd->data, sizeof(cmd->data)); 434 bus_dmamap_sync(sc->sc_dmatag, sc->sc_cmd_dmamap, BUS_DMASYNC_PREWRITE); 435 bus_space_write_4(sc->sc_bt, sc->sc_mailbox, 0, sc->sc_cmd_phys); 436 437 /* Flush the cacheline it is in -- SMU bypasses the cache */ 438 __asm __volatile("sync; dcbf 0,%0; sync" :: "r"(sc->sc_cmd): "memory"); 439 440 /* Ring SMU doorbell */ 441 macgpio_write(smu_doorbell, GPIO_DDR_OUTPUT); 442 } 443 444 static void 445 smu_doorbell_intr(void *xdev) 446 { 447 device_t smu; 448 struct smu_softc *sc; 449 int doorbell_ack; 450 451 smu = xdev; 452 doorbell_ack = macgpio_read(smu_doorbell); 453 sc = device_get_softc(smu); 454 455 if (doorbell_ack != (GPIO_DDR_OUTPUT | GPIO_LEVEL_RO | GPIO_DATA)) 456 return; 457 458 mtx_lock(&sc->sc_mtx); 459 460 if (sc->sc_cur_cmd == NULL) /* spurious */ 461 goto done; 462 463 /* Check result. First invalidate the cache again... */ 464 __asm __volatile("dcbf 0,%0; sync" :: "r"(sc->sc_cmd) : "memory"); 465 466 bus_dmamap_sync(sc->sc_dmatag, sc->sc_cmd_dmamap, BUS_DMASYNC_POSTREAD); 467 468 sc->sc_cur_cmd->cmd = sc->sc_cmd->cmd; 469 sc->sc_cur_cmd->len = sc->sc_cmd->len; 470 memcpy(sc->sc_cur_cmd->data, sc->sc_cmd->data, 471 sizeof(sc->sc_cmd->data)); 472 wakeup(sc->sc_cur_cmd); 473 sc->sc_cur_cmd = NULL; 474 if (sc->sc_u3) 475 powerpc_pow_enabled = 1; 476 477 done: 478 /* Queue next command if one is pending */ 479 if (STAILQ_FIRST(&sc->sc_cmdq) != NULL) { 480 sc->sc_cur_cmd = STAILQ_FIRST(&sc->sc_cmdq); 481 STAILQ_REMOVE_HEAD(&sc->sc_cmdq, cmd_q); 482 smu_send_cmd(smu, sc->sc_cur_cmd); 483 } 484 485 mtx_unlock(&sc->sc_mtx); 486 } 487 488 static int 489 smu_run_cmd(device_t dev, struct smu_cmd *cmd, int wait) 490 { 491 struct smu_softc *sc; 492 uint8_t cmd_code; 493 int error; 494 495 sc = device_get_softc(dev); 496 cmd_code = cmd->cmd; 497 498 mtx_lock(&sc->sc_mtx); 499 if (sc->sc_cur_cmd != NULL) { 500 STAILQ_INSERT_TAIL(&sc->sc_cmdq, cmd, cmd_q); 501 } else 502 smu_send_cmd(dev, cmd); 503 mtx_unlock(&sc->sc_mtx); 504 505 if (!wait) 506 return (0); 507 508 if (sc->sc_doorbellirqid < 0) { 509 /* Poll if the IRQ has not been set up yet */ 510 do { 511 DELAY(50); 512 smu_doorbell_intr(dev); 513 } while (sc->sc_cur_cmd != NULL); 514 } else { 515 /* smu_doorbell_intr will wake us when the command is ACK'ed */ 516 error = tsleep(cmd, 0, "smu", 800 * hz / 1000); 517 if (error != 0) 518 smu_doorbell_intr(dev); /* One last chance */ 519 520 if (error != 0) { 521 mtx_lock(&sc->sc_mtx); 522 if (cmd->cmd == cmd_code) { /* Never processed */ 523 /* Abort this command if we timed out */ 524 if (sc->sc_cur_cmd == cmd) 525 sc->sc_cur_cmd = NULL; 526 else 527 STAILQ_REMOVE(&sc->sc_cmdq, cmd, smu_cmd, 528 cmd_q); 529 mtx_unlock(&sc->sc_mtx); 530 return (error); 531 } 532 error = 0; 533 mtx_unlock(&sc->sc_mtx); 534 } 535 } 536 537 /* SMU acks the command by inverting the command bits */ 538 if (cmd->cmd == ((~cmd_code) & 0xff)) 539 error = 0; 540 else 541 error = EIO; 542 543 return (error); 544 } 545 546 static int 547 smu_get_datablock(device_t dev, int8_t id, uint8_t *buf, size_t len) 548 { 549 struct smu_cmd cmd; 550 uint8_t addr[4]; 551 552 cmd.cmd = SMU_PARTITION; 553 cmd.len = 2; 554 cmd.data[0] = SMU_PARTITION_LATEST; 555 cmd.data[1] = id; 556 557 smu_run_cmd(dev, &cmd, 1); 558 559 addr[0] = addr[1] = 0; 560 addr[2] = cmd.data[0]; 561 addr[3] = cmd.data[1]; 562 563 cmd.cmd = SMU_MISC; 564 cmd.len = 7; 565 cmd.data[0] = SMU_MISC_GET_DATA; 566 cmd.data[1] = sizeof(addr); 567 memcpy(&cmd.data[2], addr, sizeof(addr)); 568 cmd.data[6] = len; 569 570 smu_run_cmd(dev, &cmd, 1); 571 memcpy(buf, cmd.data, len); 572 return (0); 573 } 574 575 static void 576 smu_slew_cpu_voltage(device_t dev, int to) 577 { 578 struct smu_cmd cmd; 579 580 cmd.cmd = SMU_POWER; 581 cmd.len = 8; 582 cmd.data[0] = 'V'; 583 cmd.data[1] = 'S'; 584 cmd.data[2] = 'L'; 585 cmd.data[3] = 'E'; 586 cmd.data[4] = 'W'; 587 cmd.data[5] = 0xff; 588 cmd.data[6] = 1; 589 cmd.data[7] = to; 590 591 smu_run_cmd(dev, &cmd, 1); 592 } 593 594 static void 595 smu_cpufreq_pre_change(device_t dev, const struct cf_level *level) 596 { 597 /* 598 * Make sure the CPU voltage is raised before we raise 599 * the clock. 600 */ 601 602 if (level->rel_set[0].freq == 10000 /* max */) 603 smu_slew_cpu_voltage(dev, 0); 604 } 605 606 static void 607 smu_cpufreq_post_change(device_t dev, const struct cf_level *level) 608 { 609 /* We are safe to reduce CPU voltage after a downward transition */ 610 611 if (level->rel_set[0].freq < 10000 /* max */) 612 smu_slew_cpu_voltage(dev, 1); /* XXX: 1/4 voltage for 970MP? */ 613 } 614 615 /* Routines for probing the SMU doorbell GPIO */ 616 static int doorbell_probe(device_t dev); 617 static int doorbell_attach(device_t dev); 618 619 static device_method_t doorbell_methods[] = { 620 /* Device interface */ 621 DEVMETHOD(device_probe, doorbell_probe), 622 DEVMETHOD(device_attach, doorbell_attach), 623 { 0, 0 }, 624 }; 625 626 static driver_t doorbell_driver = { 627 "smudoorbell", 628 doorbell_methods, 629 0 630 }; 631 632 static devclass_t doorbell_devclass; 633 634 DRIVER_MODULE(smudoorbell, macgpio, doorbell_driver, doorbell_devclass, 0, 0); 635 636 static int 637 doorbell_probe(device_t dev) 638 { 639 const char *name = ofw_bus_get_name(dev); 640 641 if (strcmp(name, "smu-doorbell") != 0) 642 return (ENXIO); 643 644 device_set_desc(dev, "SMU Doorbell GPIO"); 645 device_quiet(dev); 646 return (0); 647 } 648 649 static int 650 doorbell_attach(device_t dev) 651 { 652 smu_doorbell = dev; 653 return (0); 654 } 655 656 /* 657 * Sensor and fan management 658 */ 659 660 static int 661 smu_fan_set_rpm(device_t smu, struct smu_fan *fan, int rpm) 662 { 663 struct smu_cmd cmd; 664 int error; 665 666 cmd.cmd = SMU_FAN; 667 error = EIO; 668 669 /* Clamp to allowed range */ 670 rpm = max(fan->min_rpm, rpm); 671 rpm = min(fan->max_rpm, rpm); 672 673 /* 674 * Apple has two fan control mechanisms. We can't distinguish 675 * them except by seeing if the new one fails. If the new one 676 * fails, use the old one. 677 */ 678 679 if (!fan->old_style) { 680 cmd.len = 4; 681 cmd.data[0] = 0x30; 682 cmd.data[1] = fan->reg; 683 cmd.data[2] = (rpm >> 8) & 0xff; 684 cmd.data[3] = rpm & 0xff; 685 686 error = smu_run_cmd(smu, &cmd, 1); 687 if (error) 688 fan->old_style = 1; 689 } 690 691 if (fan->old_style) { 692 cmd.len = 14; 693 cmd.data[0] = 0; 694 cmd.data[1] = 1 << fan->reg; 695 cmd.data[2 + 2*fan->reg] = (rpm >> 8) & 0xff; 696 cmd.data[3 + 2*fan->reg] = rpm & 0xff; 697 error = smu_run_cmd(smu, &cmd, 1); 698 } 699 700 if (error == 0) 701 fan->setpoint = rpm; 702 703 return (error); 704 } 705 706 static int 707 smu_fan_read_rpm(device_t smu, struct smu_fan *fan) 708 { 709 struct smu_cmd cmd; 710 int rpm, error; 711 712 if (!fan->old_style) { 713 cmd.cmd = SMU_FAN; 714 cmd.len = 2; 715 cmd.data[0] = 0x31; 716 cmd.data[1] = fan->reg; 717 718 error = smu_run_cmd(smu, &cmd, 1); 719 if (error) 720 fan->old_style = 1; 721 722 rpm = (cmd.data[0] << 8) | cmd.data[1]; 723 } 724 725 if (fan->old_style) { 726 cmd.cmd = SMU_FAN; 727 cmd.len = 1; 728 cmd.data[0] = 1; 729 730 error = smu_run_cmd(smu, &cmd, 1); 731 if (error) 732 return (error); 733 734 rpm = (cmd.data[fan->reg*2+1] << 8) | cmd.data[fan->reg*2+2]; 735 } 736 737 return (rpm); 738 } 739 740 static int 741 smu_fanrpm_sysctl(SYSCTL_HANDLER_ARGS) 742 { 743 device_t smu; 744 struct smu_softc *sc; 745 struct smu_fan *fan; 746 int rpm, error; 747 748 smu = arg1; 749 sc = device_get_softc(smu); 750 fan = &sc->sc_fans[arg2]; 751 752 rpm = smu_fan_read_rpm(smu, fan); 753 if (rpm < 0) 754 return (rpm); 755 756 error = sysctl_handle_int(oidp, &rpm, 0, req); 757 758 if (error || !req->newptr) 759 return (error); 760 761 sc->sc_lastuserchange = time_uptime; 762 763 return (smu_fan_set_rpm(smu, fan, rpm)); 764 } 765 766 static void 767 smu_attach_fans(device_t dev, phandle_t fanroot) 768 { 769 struct smu_fan *fan; 770 struct smu_softc *sc; 771 struct sysctl_oid *oid, *fanroot_oid; 772 struct sysctl_ctx_list *ctx; 773 phandle_t child; 774 char type[32], sysctl_name[32]; 775 int i; 776 777 sc = device_get_softc(dev); 778 sc->sc_nfans = 0; 779 780 for (child = OF_child(fanroot); child != 0; child = OF_peer(child)) 781 sc->sc_nfans++; 782 783 if (sc->sc_nfans == 0) { 784 device_printf(dev, "WARNING: No fans detected!\n"); 785 return; 786 } 787 788 sc->sc_fans = malloc(sc->sc_nfans * sizeof(struct smu_fan), M_SMU, 789 M_WAITOK | M_ZERO); 790 791 fan = sc->sc_fans; 792 sc->sc_nfans = 0; 793 794 ctx = device_get_sysctl_ctx(dev); 795 fanroot_oid = SYSCTL_ADD_NODE(ctx, 796 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "fans", 797 CTLFLAG_RD, 0, "SMU Fan Information"); 798 799 for (child = OF_child(fanroot); child != 0; child = OF_peer(child)) { 800 OF_getprop(child, "device_type", type, sizeof(type)); 801 if (strcmp(type, "fan-rpm-control") != 0) 802 continue; 803 804 fan->old_style = 0; 805 OF_getprop(child, "reg", &fan->reg, sizeof(cell_t)); 806 OF_getprop(child, "min-value", &fan->min_rpm, sizeof(cell_t)); 807 OF_getprop(child, "max-value", &fan->max_rpm, sizeof(cell_t)); 808 809 if (OF_getprop(child, "unmanaged-value", &fan->unmanaged_rpm, 810 sizeof(cell_t)) != sizeof(cell_t)) 811 fan->unmanaged_rpm = fan->max_rpm; 812 813 fan->setpoint = smu_fan_read_rpm(dev, fan); 814 815 OF_getprop(child, "location", fan->location, 816 sizeof(fan->location)); 817 818 /* Add sysctls */ 819 for (i = 0; i < strlen(fan->location); i++) { 820 sysctl_name[i] = tolower(fan->location[i]); 821 if (isspace(sysctl_name[i])) 822 sysctl_name[i] = '_'; 823 } 824 sysctl_name[i] = 0; 825 826 oid = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(fanroot_oid), 827 OID_AUTO, sysctl_name, CTLFLAG_RD, 0, "Fan Information"); 828 SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "minrpm", 829 CTLTYPE_INT | CTLFLAG_RD, &fan->min_rpm, sizeof(cell_t), 830 "Minimum allowed RPM"); 831 SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "maxrpm", 832 CTLTYPE_INT | CTLFLAG_RD, &fan->max_rpm, sizeof(cell_t), 833 "Maximum allowed RPM"); 834 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "rpm", 835 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, 836 sc->sc_nfans, smu_fanrpm_sysctl, "I", "Fan RPM"); 837 838 fan++; 839 sc->sc_nfans++; 840 } 841 } 842 843 static int 844 smu_sensor_read(device_t smu, struct smu_sensor *sens, int *val) 845 { 846 struct smu_cmd cmd; 847 struct smu_softc *sc; 848 int64_t value; 849 int error; 850 851 cmd.cmd = SMU_ADC; 852 cmd.len = 1; 853 cmd.data[0] = sens->reg; 854 error = 0; 855 856 error = smu_run_cmd(smu, &cmd, 1); 857 if (error != 0) 858 return (error); 859 860 sc = device_get_softc(smu); 861 value = (cmd.data[0] << 8) | cmd.data[1]; 862 863 switch (sens->type) { 864 case SMU_TEMP_SENSOR: 865 value *= sc->sc_cpu_diode_scale; 866 value >>= 3; 867 value += ((int64_t)sc->sc_cpu_diode_offset) << 9; 868 value <<= 1; 869 870 /* Convert from 16.16 fixed point degC into integer C. */ 871 value >>= 16; 872 break; 873 case SMU_VOLTAGE_SENSOR: 874 value *= sc->sc_cpu_volt_scale; 875 value += sc->sc_cpu_volt_offset; 876 value <<= 4; 877 878 /* Convert from 16.16 fixed point V into mV. */ 879 value *= 15625; 880 value /= 1024; 881 value /= 1000; 882 break; 883 case SMU_CURRENT_SENSOR: 884 value *= sc->sc_cpu_curr_scale; 885 value += sc->sc_cpu_curr_offset; 886 value <<= 4; 887 888 /* Convert from 16.16 fixed point A into mA. */ 889 value *= 15625; 890 value /= 1024; 891 value /= 1000; 892 break; 893 case SMU_POWER_SENSOR: 894 value *= sc->sc_slots_pow_scale; 895 value += sc->sc_slots_pow_offset; 896 value <<= 4; 897 898 /* Convert from 16.16 fixed point W into mW. */ 899 value *= 15625; 900 value /= 1024; 901 value /= 1000; 902 break; 903 } 904 905 *val = value; 906 return (0); 907 } 908 909 static int 910 smu_sensor_sysctl(SYSCTL_HANDLER_ARGS) 911 { 912 device_t smu; 913 struct smu_softc *sc; 914 struct smu_sensor *sens; 915 int value, error; 916 917 smu = arg1; 918 sc = device_get_softc(smu); 919 sens = &sc->sc_sensors[arg2]; 920 921 error = smu_sensor_read(smu, sens, &value); 922 if (error != 0) 923 return (error); 924 925 error = sysctl_handle_int(oidp, &value, 0, req); 926 927 return (error); 928 } 929 930 static void 931 smu_attach_sensors(device_t dev, phandle_t sensroot) 932 { 933 struct smu_sensor *sens; 934 struct smu_softc *sc; 935 struct sysctl_oid *sensroot_oid; 936 struct sysctl_ctx_list *ctx; 937 phandle_t child; 938 char type[32]; 939 int i; 940 941 sc = device_get_softc(dev); 942 sc->sc_nsensors = 0; 943 944 for (child = OF_child(sensroot); child != 0; child = OF_peer(child)) 945 sc->sc_nsensors++; 946 947 if (sc->sc_nsensors == 0) { 948 device_printf(dev, "WARNING: No sensors detected!\n"); 949 return; 950 } 951 952 sc->sc_sensors = malloc(sc->sc_nsensors * sizeof(struct smu_sensor), 953 M_SMU, M_WAITOK | M_ZERO); 954 955 sens = sc->sc_sensors; 956 sc->sc_nsensors = 0; 957 958 ctx = device_get_sysctl_ctx(dev); 959 sensroot_oid = SYSCTL_ADD_NODE(ctx, 960 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "sensors", 961 CTLFLAG_RD, 0, "SMU Sensor Information"); 962 963 for (child = OF_child(sensroot); child != 0; child = OF_peer(child)) { 964 char sysctl_name[40], sysctl_desc[40]; 965 const char *units; 966 967 OF_getprop(child, "device_type", type, sizeof(type)); 968 969 if (strcmp(type, "current-sensor") == 0) { 970 sens->type = SMU_CURRENT_SENSOR; 971 units = "mA"; 972 } else if (strcmp(type, "temp-sensor") == 0) { 973 sens->type = SMU_TEMP_SENSOR; 974 units = "C"; 975 } else if (strcmp(type, "voltage-sensor") == 0) { 976 sens->type = SMU_VOLTAGE_SENSOR; 977 units = "mV"; 978 } else if (strcmp(type, "power-sensor") == 0) { 979 sens->type = SMU_POWER_SENSOR; 980 units = "mW"; 981 } else { 982 continue; 983 } 984 985 OF_getprop(child, "reg", &sens->reg, sizeof(cell_t)); 986 OF_getprop(child, "location", sens->location, 987 sizeof(sens->location)); 988 989 for (i = 0; i < strlen(sens->location); i++) { 990 sysctl_name[i] = tolower(sens->location[i]); 991 if (isspace(sysctl_name[i])) 992 sysctl_name[i] = '_'; 993 } 994 sysctl_name[i] = 0; 995 996 sprintf(sysctl_desc,"%s (%s)", sens->location, units); 997 998 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(sensroot_oid), OID_AUTO, 999 sysctl_name, CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, 1000 dev, sc->sc_nsensors, smu_sensor_sysctl, "I", sysctl_desc); 1001 1002 sens++; 1003 sc->sc_nsensors++; 1004 } 1005 } 1006 1007 static void 1008 smu_fan_management_proc(void *xdev) 1009 { 1010 device_t smu = xdev; 1011 1012 while(1) { 1013 smu_manage_fans(smu); 1014 pause("smu", SMU_FANMGT_INTERVAL * hz / 1000); 1015 } 1016 } 1017 1018 static void 1019 smu_manage_fans(device_t smu) 1020 { 1021 struct smu_softc *sc; 1022 int i, maxtemp, temp, factor, error; 1023 1024 sc = device_get_softc(smu); 1025 1026 maxtemp = 0; 1027 for (i = 0; i < sc->sc_nsensors; i++) { 1028 if (sc->sc_sensors[i].type != SMU_TEMP_SENSOR) 1029 continue; 1030 1031 error = smu_sensor_read(smu, &sc->sc_sensors[i], &temp); 1032 if (error == 0 && temp > maxtemp) 1033 maxtemp = temp; 1034 } 1035 1036 if (maxtemp > sc->sc_critical_temp) { 1037 device_printf(smu, "WARNING: Current system temperature (%d C) " 1038 "exceeds critical temperature (%d C)! Shutting down!\n", 1039 maxtemp, sc->sc_critical_temp); 1040 shutdown_nice(RB_POWEROFF); 1041 } 1042 1043 if (maxtemp - sc->sc_target_temp > 20) 1044 device_printf(smu, "WARNING: Current system temperature (%d C) " 1045 "more than 20 degrees over target temperature (%d C)!\n", 1046 maxtemp, sc->sc_target_temp); 1047 1048 if (time_uptime - sc->sc_lastuserchange < 3) { 1049 /* 1050 * If we have heard from a user process in the last 3 seconds, 1051 * go away. 1052 */ 1053 1054 return; 1055 } 1056 1057 if (maxtemp < 10) { /* Bail if no good sensors */ 1058 for (i = 0; i < sc->sc_nfans; i++) 1059 smu_fan_set_rpm(smu, &sc->sc_fans[i], 1060 sc->sc_fans[i].unmanaged_rpm); 1061 return; 1062 } 1063 1064 if (maxtemp - sc->sc_target_temp > 4) 1065 factor = 110; 1066 else if (maxtemp - sc->sc_target_temp > 1) 1067 factor = 105; 1068 else if (sc->sc_target_temp - maxtemp > 4) 1069 factor = 90; 1070 else if (sc->sc_target_temp - maxtemp > 1) 1071 factor = 95; 1072 else 1073 factor = 100; 1074 1075 for (i = 0; i < sc->sc_nfans; i++) 1076 smu_fan_set_rpm(smu, &sc->sc_fans[i], 1077 (sc->sc_fans[i].setpoint * factor) / 100); 1078 } 1079 1080 static void 1081 smu_set_sleepled(void *xdev, int onoff) 1082 { 1083 static struct smu_cmd cmd; 1084 device_t smu = xdev; 1085 1086 cmd.cmd = SMU_MISC; 1087 cmd.len = 3; 1088 cmd.data[0] = SMU_MISC_LED_CTRL; 1089 cmd.data[1] = 0; 1090 cmd.data[2] = onoff; 1091 1092 smu_run_cmd(smu, &cmd, 0); 1093 } 1094 1095 static int 1096 smu_server_mode(SYSCTL_HANDLER_ARGS) 1097 { 1098 struct smu_cmd cmd; 1099 u_int server_mode; 1100 device_t smu = arg1; 1101 int error; 1102 1103 cmd.cmd = SMU_POWER_EVENTS; 1104 cmd.len = 1; 1105 cmd.data[0] = SMU_PWR_GET_POWERUP; 1106 1107 error = smu_run_cmd(smu, &cmd, 1); 1108 1109 if (error) 1110 return (error); 1111 1112 server_mode = (cmd.data[1] & SMU_WAKEUP_AC_INSERT) ? 1 : 0; 1113 1114 error = sysctl_handle_int(oidp, &server_mode, 0, req); 1115 1116 if (error || !req->newptr) 1117 return (error); 1118 1119 if (server_mode == 1) 1120 cmd.data[0] = SMU_PWR_SET_POWERUP; 1121 else if (server_mode == 0) 1122 cmd.data[0] = SMU_PWR_CLR_POWERUP; 1123 else 1124 return (EINVAL); 1125 1126 cmd.len = 3; 1127 cmd.data[1] = 0; 1128 cmd.data[2] = SMU_WAKEUP_AC_INSERT; 1129 1130 return (smu_run_cmd(smu, &cmd, 1)); 1131 } 1132 1133 static void 1134 smu_shutdown(void *xdev, int howto) 1135 { 1136 device_t smu = xdev; 1137 struct smu_cmd cmd; 1138 1139 cmd.cmd = SMU_POWER; 1140 if (howto & RB_HALT) 1141 strcpy(cmd.data, "SHUTDOWN"); 1142 else 1143 strcpy(cmd.data, "RESTART"); 1144 1145 cmd.len = strlen(cmd.data); 1146 1147 smu_run_cmd(smu, &cmd, 1); 1148 1149 for (;;); 1150 } 1151 1152 static int 1153 smu_gettime(device_t dev, struct timespec *ts) 1154 { 1155 struct smu_cmd cmd; 1156 struct clocktime ct; 1157 1158 cmd.cmd = SMU_RTC; 1159 cmd.len = 1; 1160 cmd.data[0] = SMU_RTC_GET; 1161 1162 if (smu_run_cmd(dev, &cmd, 1) != 0) 1163 return (ENXIO); 1164 1165 ct.nsec = 0; 1166 ct.sec = bcd2bin(cmd.data[0]); 1167 ct.min = bcd2bin(cmd.data[1]); 1168 ct.hour = bcd2bin(cmd.data[2]); 1169 ct.dow = bcd2bin(cmd.data[3]); 1170 ct.day = bcd2bin(cmd.data[4]); 1171 ct.mon = bcd2bin(cmd.data[5]); 1172 ct.year = bcd2bin(cmd.data[6]) + 2000; 1173 1174 return (clock_ct_to_ts(&ct, ts)); 1175 } 1176 1177 static int 1178 smu_settime(device_t dev, struct timespec *ts) 1179 { 1180 struct smu_cmd cmd; 1181 struct clocktime ct; 1182 1183 cmd.cmd = SMU_RTC; 1184 cmd.len = 8; 1185 cmd.data[0] = SMU_RTC_SET; 1186 1187 clock_ts_to_ct(ts, &ct); 1188 1189 cmd.data[1] = bin2bcd(ct.sec); 1190 cmd.data[2] = bin2bcd(ct.min); 1191 cmd.data[3] = bin2bcd(ct.hour); 1192 cmd.data[4] = bin2bcd(ct.dow); 1193 cmd.data[5] = bin2bcd(ct.day); 1194 cmd.data[6] = bin2bcd(ct.mon); 1195 cmd.data[7] = bin2bcd(ct.year - 2000); 1196 1197 return (smu_run_cmd(dev, &cmd, 1)); 1198 } 1199 1200 /* SMU I2C Interface */ 1201 1202 static int smuiic_probe(device_t dev); 1203 static int smuiic_attach(device_t dev); 1204 static int smuiic_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs); 1205 static phandle_t smuiic_get_node(device_t bus, device_t dev); 1206 1207 static device_method_t smuiic_methods[] = { 1208 /* device interface */ 1209 DEVMETHOD(device_probe, smuiic_probe), 1210 DEVMETHOD(device_attach, smuiic_attach), 1211 1212 /* iicbus interface */ 1213 DEVMETHOD(iicbus_callback, iicbus_null_callback), 1214 DEVMETHOD(iicbus_transfer, smuiic_transfer), 1215 1216 /* ofw_bus interface */ 1217 DEVMETHOD(ofw_bus_get_node, smuiic_get_node), 1218 1219 { 0, 0 } 1220 }; 1221 1222 struct smuiic_softc { 1223 struct mtx sc_mtx; 1224 volatile int sc_iic_inuse; 1225 int sc_busno; 1226 }; 1227 1228 static driver_t smuiic_driver = { 1229 "iichb", 1230 smuiic_methods, 1231 sizeof(struct smuiic_softc) 1232 }; 1233 static devclass_t smuiic_devclass; 1234 1235 DRIVER_MODULE(smuiic, smu, smuiic_driver, smuiic_devclass, 0, 0); 1236 1237 static void 1238 smu_attach_i2c(device_t smu, phandle_t i2croot) 1239 { 1240 phandle_t child; 1241 device_t cdev; 1242 struct ofw_bus_devinfo *dinfo; 1243 char name[32]; 1244 1245 for (child = OF_child(i2croot); child != 0; child = OF_peer(child)) { 1246 if (OF_getprop(child, "name", name, sizeof(name)) <= 0) 1247 continue; 1248 1249 if (strcmp(name, "i2c-bus") != 0 && strcmp(name, "i2c") != 0) 1250 continue; 1251 1252 dinfo = malloc(sizeof(struct ofw_bus_devinfo), M_SMU, 1253 M_WAITOK | M_ZERO); 1254 if (ofw_bus_gen_setup_devinfo(dinfo, child) != 0) { 1255 free(dinfo, M_SMU); 1256 continue; 1257 } 1258 1259 cdev = device_add_child(smu, NULL, -1); 1260 if (cdev == NULL) { 1261 device_printf(smu, "<%s>: device_add_child failed\n", 1262 dinfo->obd_name); 1263 ofw_bus_gen_destroy_devinfo(dinfo); 1264 free(dinfo, M_SMU); 1265 continue; 1266 } 1267 device_set_ivars(cdev, dinfo); 1268 } 1269 } 1270 1271 static int 1272 smuiic_probe(device_t dev) 1273 { 1274 const char *name; 1275 1276 name = ofw_bus_get_name(dev); 1277 if (name == NULL) 1278 return (ENXIO); 1279 1280 if (strcmp(name, "i2c-bus") == 0 || strcmp(name, "i2c") == 0) { 1281 device_set_desc(dev, "SMU I2C controller"); 1282 return (0); 1283 } 1284 1285 return (ENXIO); 1286 } 1287 1288 static int 1289 smuiic_attach(device_t dev) 1290 { 1291 struct smuiic_softc *sc = device_get_softc(dev); 1292 mtx_init(&sc->sc_mtx, "smuiic", NULL, MTX_DEF); 1293 sc->sc_iic_inuse = 0; 1294 1295 /* Get our bus number */ 1296 OF_getprop(ofw_bus_get_node(dev), "reg", &sc->sc_busno, 1297 sizeof(sc->sc_busno)); 1298 1299 /* Add the IIC bus layer */ 1300 device_add_child(dev, "iicbus", -1); 1301 1302 return (bus_generic_attach(dev)); 1303 } 1304 1305 static int 1306 smuiic_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs) 1307 { 1308 struct smuiic_softc *sc = device_get_softc(dev); 1309 struct smu_cmd cmd; 1310 int i, j, error; 1311 1312 mtx_lock(&sc->sc_mtx); 1313 while (sc->sc_iic_inuse) 1314 mtx_sleep(sc, &sc->sc_mtx, 0, "smuiic", 100); 1315 1316 sc->sc_iic_inuse = 1; 1317 error = 0; 1318 1319 for (i = 0; i < nmsgs; i++) { 1320 cmd.cmd = SMU_I2C; 1321 cmd.data[0] = sc->sc_busno; 1322 if (msgs[i].flags & IIC_M_NOSTOP) 1323 cmd.data[1] = SMU_I2C_COMBINED; 1324 else 1325 cmd.data[1] = SMU_I2C_SIMPLE; 1326 1327 cmd.data[2] = msgs[i].slave; 1328 if (msgs[i].flags & IIC_M_RD) 1329 cmd.data[2] |= 1; 1330 1331 if (msgs[i].flags & IIC_M_NOSTOP) { 1332 KASSERT(msgs[i].len < 4, 1333 ("oversize I2C combined message")); 1334 1335 cmd.data[3] = min(msgs[i].len, 3); 1336 memcpy(&cmd.data[4], msgs[i].buf, min(msgs[i].len, 3)); 1337 i++; /* Advance to next part of message */ 1338 } else { 1339 cmd.data[3] = 0; 1340 memset(&cmd.data[4], 0, 3); 1341 } 1342 1343 cmd.data[7] = msgs[i].slave; 1344 if (msgs[i].flags & IIC_M_RD) 1345 cmd.data[7] |= 1; 1346 1347 cmd.data[8] = msgs[i].len; 1348 if (msgs[i].flags & IIC_M_RD) { 1349 memset(&cmd.data[9], 0xff, msgs[i].len); 1350 cmd.len = 9; 1351 } else { 1352 memcpy(&cmd.data[9], msgs[i].buf, msgs[i].len); 1353 cmd.len = 9 + msgs[i].len; 1354 } 1355 1356 mtx_unlock(&sc->sc_mtx); 1357 smu_run_cmd(device_get_parent(dev), &cmd, 1); 1358 mtx_lock(&sc->sc_mtx); 1359 1360 for (j = 0; j < 10; j++) { 1361 cmd.cmd = SMU_I2C; 1362 cmd.len = 1; 1363 cmd.data[0] = 0; 1364 memset(&cmd.data[1], 0xff, msgs[i].len); 1365 1366 mtx_unlock(&sc->sc_mtx); 1367 smu_run_cmd(device_get_parent(dev), &cmd, 1); 1368 mtx_lock(&sc->sc_mtx); 1369 1370 if (!(cmd.data[0] & 0x80)) 1371 break; 1372 1373 mtx_sleep(sc, &sc->sc_mtx, 0, "smuiic", 10); 1374 } 1375 1376 if (cmd.data[0] & 0x80) { 1377 error = EIO; 1378 msgs[i].len = 0; 1379 goto exit; 1380 } 1381 memcpy(msgs[i].buf, &cmd.data[1], msgs[i].len); 1382 msgs[i].len = cmd.len - 1; 1383 } 1384 1385 exit: 1386 sc->sc_iic_inuse = 0; 1387 mtx_unlock(&sc->sc_mtx); 1388 wakeup(sc); 1389 return (error); 1390 } 1391 1392 static phandle_t 1393 smuiic_get_node(device_t bus, device_t dev) 1394 { 1395 1396 return (ofw_bus_get_node(bus)); 1397 } 1398 1399