11797Sphk/* $OpenBSD: smu.c,v 1.35 2022/03/13 12:33:01 mpi Exp $ */ 21797Sphk 31797Sphk/* 41797Sphk * Copyright (c) 2005 Mark Kettenis 51797Sphk * 61797Sphk * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19#include <sys/param.h> 20#include <sys/systm.h> 21#include <sys/device.h> 22#include <sys/kernel.h> 23#include <sys/rwlock.h> 24#include <sys/proc.h> 25#include <sys/sensors.h> 26 27#include <machine/autoconf.h> 28#include <machine/cpu.h> 29 30#include <dev/clock_subr.h> 31#include <dev/i2c/i2cvar.h> 32#include <dev/ofw/openfirm.h> 33 34#include <macppc/dev/maci2cvar.h> 35#include <macppc/dev/thermal.h> 36#include <macppc/pci/macobio.h> 37 38int smu_match(struct device *, void *, void *); 39void smu_attach(struct device *, struct device *, void *); 40 41/* Target and Max. temperature in muK. */ 42#define TEMP_TRG 38 * 1000000 + 273150000 43#define TEMP_MAX 70 * 1000000 + 273150000 44 45#define SMU_MAXFANS 8 46 47struct smu_fan { 48 struct thermal_fan fan; 49 u_int8_t reg; 50 u_int16_t min_rpm; 51 u_int16_t max_rpm; 52 u_int16_t unmanaged_rpm; 53 u_int16_t min_pwm; 54 u_int16_t max_pwm; 55 u_int16_t unmanaged_pwm; 56 struct ksensor sensor; 57}; 58 59#define SMU_MAXSENSORS 4 60 61struct smu_sensor { 62 struct thermal_temp therm; 63 u_int8_t reg; 64 struct ksensor sensor; 65}; 66 67struct smu_softc { 68 struct device sc_dev; 69 70 /* SMU command buffer. */ 71 bus_dma_tag_t sc_dmat; 72 bus_dmamap_t sc_cmdmap; 73 bus_dma_segment_t sc_cmdseg[1]; 74 caddr_t sc_cmd; 75 struct rwlock sc_lock; 76 77 /* Doorbell and mailbox. */ 78 struct ppc_bus_space sc_mem_bus_space; 79 bus_space_tag_t sc_memt; 80 bus_space_handle_t sc_gpioh; 81 bus_space_handle_t sc_buffh; 82 83 uint8_t sc_firmware_old; 84 85 struct smu_fan sc_fans[SMU_MAXFANS]; 86 int sc_num_fans; 87 88 struct smu_sensor sc_sensors[SMU_MAXSENSORS]; 89 int sc_num_sensors; 90 91 struct ksensordev sc_sensordev; 92 93 u_int16_t sc_cpu_diode_scale; 94 int16_t sc_cpu_diode_offset; 95 u_int16_t sc_cpu_volt_scale; 96 int16_t sc_cpu_volt_offset; 97 u_int16_t sc_cpu_curr_scale; 98 int16_t sc_cpu_curr_offset; 99 100 u_int16_t sc_slots_pow_scale; 101 int16_t sc_slots_pow_offset; 102 103 struct i2c_controller sc_i2c_tag; 104}; 105 106const struct cfattach smu_ca = { 107 sizeof(struct smu_softc), smu_match, smu_attach 108}; 109 110struct cfdriver smu_cd = { 111 NULL, "smu", DV_DULL, 112}; 113 114/* SMU command */ 115struct smu_cmd { 116 u_int8_t cmd; 117 u_int8_t len; 118 u_int8_t data[254]; 119}; 120#define SMU_CMDSZ sizeof(struct smu_cmd) 121 122/* RTC */ 123#define SMU_RTC 0x8e 124#define SMU_RTC_SET_DATETIME 0x80 125#define SMU_RTC_GET_DATETIME 0x81 126 127/* ADC */ 128#define SMU_ADC 0xd8 129 130/* Fan control */ 131#define SMU_FAN 0x4a 132 133/* Data partitions */ 134#define SMU_PARTITION 0x3e 135#define SMU_PARTITION_LATEST 0x01 136#define SMU_PARTITION_BASE 0x02 137#define SMU_PARTITION_UPDATE 0x03 138 139/* I2C */ 140#define SMU_I2C 0x9a 141#define SMU_I2C_SIMPLE 0x00 142#define SMU_I2C_NORMAL 0x01 143#define SMU_I2C_COMBINED 0x02 144 145/* Power Management */ 146#define SMU_POWER 0xaa 147 148/* Miscellaneous */ 149#define SMU_MISC 0xee 150#define SMU_MISC_GET_DATA 0x02 151 152int smu_intr(void *); 153 154int smu_do_cmd(struct smu_softc *, int); 155int smu_time_read(time_t *); 156int smu_time_write(time_t); 157int smu_get_datablock(struct smu_softc *sc, u_int8_t, u_int8_t *, size_t); 158void smu_firmware_probe(struct smu_softc *, struct smu_fan *); 159int smu_fan_set_rpm(struct smu_softc *, struct smu_fan *, u_int16_t); 160int smu_fan_set_pwm(struct smu_softc *, struct smu_fan *, u_int16_t); 161int smu_fan_read_rpm(struct smu_softc *, struct smu_fan *, u_int16_t *); 162int smu_fan_read_pwm(struct smu_softc *, struct smu_fan *, u_int16_t *, 163 u_int16_t *); 164int smu_fan_refresh(struct smu_softc *, struct smu_fan *); 165int smu_sensor_refresh(struct smu_softc *, struct smu_sensor *, int); 166void smu_refresh_sensors(void *); 167 168int smu_fan_set_rpm_thermal(struct smu_fan *, int); 169int smu_fan_set_pwm_thermal(struct smu_fan *, int); 170int smu_sensor_refresh_thermal(struct smu_sensor *); 171 172int smu_i2c_acquire_bus(void *, int); 173void smu_i2c_release_bus(void *, int); 174int smu_i2c_exec(void *, i2c_op_t, i2c_addr_t, 175 const void *, size_t, void *buf, size_t, int); 176 177void smu_slew_voltage(u_int); 178 179int 180smu_match(struct device *parent, void *cf, void *aux) 181{ 182 struct confargs *ca = aux; 183 184 if (strcmp(ca->ca_name, "smu") == 0) 185 return (1); 186 return (0); 187} 188 189/* XXX */ 190extern struct powerpc_bus_dma_tag pci_bus_dma_tag; 191 192void 193smu_attach(struct device *parent, struct device *self, void *aux) 194{ 195 struct smu_softc *sc = (struct smu_softc *)self; 196 struct confargs *ca = aux; 197 struct i2cbus_attach_args iba; 198 struct smu_fan *fan; 199 struct smu_sensor *sensor; 200 int nseg, node; 201 char type[32], loc[32]; 202 u_int32_t reg, intr, gpio, val; 203#ifndef SMALL_KERNEL 204 u_int8_t data[12]; 205#endif 206 207 /* XXX */ 208 sc->sc_mem_bus_space.bus_base = 0x80000000; 209 sc->sc_mem_bus_space.bus_size = 0; 210 sc->sc_mem_bus_space.bus_io = 0; 211 sc->sc_memt = &sc->sc_mem_bus_space; 212 213 /* Map smu-doorbell gpio. */ 214 if (OF_getprop(ca->ca_node, "platform-doorbell-ack", 215 &node, sizeof node) <= 0 || 216 OF_getprop(node, "reg", ®, sizeof reg) <= 0 || 217 OF_getprop(node, "interrupts", &intr, sizeof intr) <= 0 || 218 OF_getprop(OF_parent(node), "reg", &gpio, sizeof gpio) <= 0) { 219 printf(": cannot find smu-doorbell gpio\n"); 220 return; 221 } 222 if (bus_space_map(sc->sc_memt, gpio + reg, 1, 0, &sc->sc_gpioh)) { 223 printf(": cannot map smu-doorbell gpio\n"); 224 return; 225 } 226 227 /* XXX Should get this from OF. */ 228 if (bus_space_map(sc->sc_memt, 0x860c, 4, 0, &sc->sc_buffh)) { 229 printf(": cannot map smu-doorbell buffer\n"); 230 return; 231 } 232 233 /* XXX */ 234 sc->sc_dmat = &pci_bus_dma_tag; 235 236 /* Allocate and map SMU command buffer. */ 237 if (bus_dmamem_alloc(sc->sc_dmat, SMU_CMDSZ, 0, 0, 238 sc->sc_cmdseg, 1, &nseg, BUS_DMA_NOWAIT)) { 239 printf(": cannot allocate cmd buffer\n"); 240 return; 241 } 242 if (bus_dmamem_map(sc->sc_dmat, sc->sc_cmdseg, nseg, 243 SMU_CMDSZ, &sc->sc_cmd, BUS_DMA_NOWAIT)) { 244 printf(": cannot map cmd buffer\n"); 245 bus_dmamem_free(sc->sc_dmat, sc->sc_cmdseg, 1); 246 return; 247 } 248 if (bus_dmamap_create(sc->sc_dmat, SMU_CMDSZ, 1, SMU_CMDSZ, 0, 249 BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &sc->sc_cmdmap)) { 250 printf(": cannot create cmd dmamap\n"); 251 bus_dmamem_unmap(sc->sc_dmat, sc->sc_cmd, SMU_CMDSZ); 252 bus_dmamem_free(sc->sc_dmat, sc->sc_cmdseg, 1); 253 return; 254 } 255 if (bus_dmamap_load(sc->sc_dmat, sc->sc_cmdmap, sc->sc_cmd, 256 SMU_CMDSZ, NULL, BUS_DMA_NOWAIT)) { 257 printf(": cannot load cmd dmamap\n"); 258 bus_dmamap_destroy(sc->sc_dmat, sc->sc_cmdmap); 259 bus_dmamem_unmap(sc->sc_dmat, sc->sc_cmd, SMU_CMDSZ); 260 bus_dmamem_free(sc->sc_dmat, sc->sc_cmdseg, nseg); 261 return; 262 } 263 264 rw_init(&sc->sc_lock, sc->sc_dev.dv_xname); 265 266 /* Establish smu-doorbell interrupt. */ 267 mac_intr_establish(parent, intr, IST_EDGE, IPL_BIO, 268 smu_intr, sc, sc->sc_dev.dv_xname); 269 270 /* Initialize global variables that control RTC functionality. */ 271 time_read = smu_time_read; 272 time_write = smu_time_write; 273 274 /* RPM Fans */ 275 node = OF_getnodebyname(ca->ca_node, "rpm-fans"); 276 if (node == 0) 277 node = OF_getnodebyname(ca->ca_node, "fans"); 278 for (node = OF_child(node); node; node = OF_peer(node)) { 279 if (OF_getprop(node, "reg", ®, sizeof reg) <= 0 || 280 OF_getprop(node, "device_type", type, sizeof type) <= 0) 281 continue; 282 283 if (strcmp(type, "fan-rpm-control") != 0) { 284 printf(": unsupported rpm-fan type: %s\n", type); 285 return; 286 } 287 288 if (sc->sc_num_fans >= SMU_MAXFANS) { 289 printf(": too many fans\n"); 290 return; 291 } 292 293 fan = &sc->sc_fans[sc->sc_num_fans++]; 294 fan->sensor.type = SENSOR_FANRPM; 295 fan->sensor.flags = SENSOR_FINVALID; 296 fan->reg = reg; 297 298 if (OF_getprop(node, "min-value", &val, sizeof val) <= 0) 299 val = 0; 300 fan->min_rpm = val; 301 if (OF_getprop(node, "max-value", &val, sizeof val) <= 0) 302 val = 0xffff; 303 fan->max_rpm = val; 304 if (OF_getprop(node, "unmanage-value", &val, sizeof val) > 0) 305 fan->unmanaged_rpm = val; 306 else if (OF_getprop(node, "safe-value", &val, sizeof val) > 0) 307 fan->unmanaged_rpm = val; 308 else 309 fan->unmanaged_rpm = fan->max_rpm; 310 311 if (OF_getprop(node, "location", loc, sizeof loc) <= 0) 312 strlcpy(loc, "Unknown", sizeof loc); 313 strlcpy(fan->sensor.desc, loc, sizeof sensor->sensor.desc); 314 315 /* Start running fans at their "unmanaged" speed. */ 316 smu_fan_set_rpm(sc, fan, fan->unmanaged_rpm); 317 318 /* Register fan at thermal management framework. */ 319 fan->fan.min_rpm = fan->min_rpm; 320 fan->fan.max_rpm = fan->max_rpm; 321 fan->fan.default_rpm = fan->unmanaged_rpm; 322 strlcpy(fan->fan.name, loc, sizeof fan->fan.name); 323 OF_getprop(node, "zone", &fan->fan.zone, sizeof fan->fan.zone); 324 fan->fan.set = (int (*)(struct thermal_fan *, int)) 325 smu_fan_set_rpm_thermal; 326 thermal_fan_register(&fan->fan); 327#ifndef SMALL_KERNEL 328 sensor_attach(&sc->sc_sensordev, &fan->sensor); 329#endif 330 } 331 332 /* PWM Fans */ 333 node = OF_getnodebyname(ca->ca_node, "pwm-fans"); 334 for (node = OF_child(node); node; node = OF_peer(node)) { 335 if (OF_getprop(node, "reg", ®, sizeof reg) <= 0 || 336 OF_getprop(node, "device_type", type, sizeof type) <= 0) 337 continue; 338 339 if (strcmp(type, "fan-pwm-control") != 0) { 340 printf(": unsupported pwm-fan type: %s\n", type); 341 return; 342 } 343 344 if (sc->sc_num_fans >= SMU_MAXFANS) { 345 printf(": too many fans\n"); 346 return; 347 } 348 349 fan = &sc->sc_fans[sc->sc_num_fans++]; 350 fan->sensor.type = SENSOR_PERCENT; 351 fan->sensor.flags = SENSOR_FINVALID; 352 fan->reg = reg; 353 354 if (OF_getprop(node, "min-value", &val, sizeof val) <= 0) 355 val = 0; 356 fan->min_pwm = val; 357 if (OF_getprop(node, "max-value", &val, sizeof val) <= 0) 358 val = 0xffff; 359 fan->max_pwm = val; 360 if (OF_getprop(node, "unmanage-value", &val, sizeof val) > 0) 361 fan->unmanaged_pwm = val; 362 else if (OF_getprop(node, "safe-value", &val, sizeof val) > 0) 363 fan->unmanaged_pwm = val; 364 else 365 fan->unmanaged_pwm = fan->min_pwm; 366 367 if (OF_getprop(node, "location", loc, sizeof loc) <= 0) 368 strlcpy(loc, "Unknown", sizeof loc); 369 strlcpy(fan->sensor.desc, loc, sizeof sensor->sensor.desc); 370 371 /* Start running fans at their "unmanaged" speed. */ 372 smu_fan_set_pwm(sc, fan, fan->unmanaged_pwm); 373 374 /* Register fan at thermal management framework. */ 375 fan->fan.min_rpm = fan->min_pwm; 376 fan->fan.max_rpm = fan->max_pwm; 377 fan->fan.default_rpm = fan->unmanaged_pwm; 378 strlcpy(fan->fan.name, loc, sizeof fan->fan.name); 379 OF_getprop(node, "zone", &fan->fan.zone, sizeof fan->fan.zone); 380 fan->fan.set = (int (*)(struct thermal_fan *, int)) 381 smu_fan_set_pwm_thermal; 382 thermal_fan_register(&fan->fan); 383#ifndef SMALL_KERNEL 384 sensor_attach(&sc->sc_sensordev, &fan->sensor); 385#endif 386 } 387 388 /* 389 * Bail out if we didn't find any fans. If we don't set the 390 * fans to a safe speed, but tickle the SMU periodically by 391 * reading sensors, the fans will never spin up and the 392 * machine might overheat. 393 */ 394 if (sc->sc_num_fans == 0) { 395 printf(": no fans\n"); 396 return; 397 } 398 399 /* Probe the smu firmware version */ 400 smu_firmware_probe(sc, &sc->sc_fans[0]); 401 402#ifndef SMALL_KERNEL 403 /* Sensors */ 404 node = OF_getnodebyname(ca->ca_node, "sensors"); 405 for (node = OF_child(node); node; node = OF_peer(node)) { 406 if (OF_getprop(node, "reg", &val, sizeof val) <= 0 || 407 OF_getprop(node, "device_type", type, sizeof type) <= 0) 408 continue; 409 410 if (sc->sc_num_sensors >= SMU_MAXSENSORS) { 411 printf(": too many sensors\n"); 412 return; 413 } 414 415 sensor = &sc->sc_sensors[sc->sc_num_sensors++]; 416 sensor->sensor.flags = SENSOR_FINVALID; 417 sensor->reg = val; 418 419 if (strcmp(type, "current-sensor") == 0) { 420 sensor->sensor.type = SENSOR_AMPS; 421 } else if (strcmp(type, "temp-sensor") == 0) { 422 sensor->sensor.type = SENSOR_TEMP; 423 } else if (strcmp(type, "voltage-sensor") == 0) { 424 sensor->sensor.type = SENSOR_VOLTS_DC; 425 } else if (strcmp(type, "power-sensor") == 0) { 426 sensor->sensor.type = SENSOR_WATTS; 427 } else { 428 sensor->sensor.type = SENSOR_INTEGER; 429 } 430 431 if (OF_getprop(node, "location", loc, sizeof loc) <= 0) 432 strlcpy(loc, "Unknown", sizeof loc); 433 strlcpy(sensor->sensor.desc, loc, sizeof sensor->sensor.desc); 434 435 /* Register temp. sensor at thermal management framework. */ 436 if (sensor->sensor.type == SENSOR_TEMP) { 437 sensor->therm.target_temp = TEMP_TRG; 438 sensor->therm.max_temp = TEMP_MAX; 439 strlcpy(sensor->therm.name, loc, 440 sizeof sensor->therm.name); 441 OF_getprop(node, "zone", &sensor->therm.zone, 442 sizeof sensor->therm.zone); 443 sensor->therm.read = (int (*) 444 (struct thermal_temp *))smu_sensor_refresh_thermal; 445 thermal_sensor_register(&sensor->therm); 446 } 447 448 sensor_attach(&sc->sc_sensordev, &sensor->sensor); 449 } 450 451 /* Register sensor device with sysctl */ 452 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, 453 sizeof(sc->sc_sensordev.xname)); 454 sensordev_install(&sc->sc_sensordev); 455 456 /* CPU temperature diode calibration */ 457 smu_get_datablock(sc, 0x18, data, sizeof data); 458 sc->sc_cpu_diode_scale = (data[4] << 8) + data[5]; 459 sc->sc_cpu_diode_offset = (data[6] << 8) + data[7]; 460 461 /* CPU power (voltage and current) calibration */ 462 smu_get_datablock(sc, 0x21, data, sizeof data); 463 sc->sc_cpu_volt_scale = (data[4] << 8) + data[5]; 464 sc->sc_cpu_volt_offset = (data[6] << 8) + data[7]; 465 sc->sc_cpu_curr_scale = (data[8] << 8) + data[9]; 466 sc->sc_cpu_curr_offset = (data[10] << 8) + data[11]; 467 468 /* Slots power calibration */ 469 smu_get_datablock(sc, 0x78, data, sizeof data); 470 sc->sc_slots_pow_scale = (data[4] << 8) + data[5]; 471 sc->sc_slots_pow_offset = (data[6] << 8) + data[7]; 472 473 sensor_task_register(sc, smu_refresh_sensors, 5); 474#endif /* !SMALL_KERNEL */ 475 printf("\n"); 476 477 ppc64_slew_voltage = smu_slew_voltage; 478 479 sc->sc_i2c_tag.ic_cookie = sc; 480 sc->sc_i2c_tag.ic_acquire_bus = smu_i2c_acquire_bus; 481 sc->sc_i2c_tag.ic_release_bus = smu_i2c_release_bus; 482 sc->sc_i2c_tag.ic_exec = smu_i2c_exec; 483 484 /* 485 * Early versions of the SMU have the i2c bus node directly 486 * below the "smu" node, while later models have an 487 * intermediate "smu-i2c-control" node. 488 */ 489 node = OF_getnodebyname(ca->ca_node, "smu-i2c-control"); 490 if (node) 491 node = OF_child(node); 492 else 493 node = OF_getnodebyname(ca->ca_node, "i2c"); 494 495 bzero(&iba, sizeof iba); 496 iba.iba_name = "iic"; 497 iba.iba_tag = &sc->sc_i2c_tag; 498 iba.iba_bus_scan = maciic_scan; 499 iba.iba_bus_scan_arg = &node; 500 config_found(&sc->sc_dev, &iba, NULL); 501} 502 503int 504smu_intr(void *arg) 505{ 506 wakeup(arg); 507 return 1; 508} 509 510int 511smu_do_cmd(struct smu_softc *sc, int msecs) 512{ 513 struct smu_cmd *cmd = (struct smu_cmd *)sc->sc_cmd; 514 u_int8_t gpio, ack = ~cmd->cmd; 515 int error; 516 517 /* Write to mailbox. */ 518 bus_space_write_4(sc->sc_memt, sc->sc_buffh, 0, 519 sc->sc_cmdmap->dm_segs->ds_addr); 520 521 /* Flush to RAM. */ 522 asm volatile ("dcbst 0,%0; sync" :: "r"(sc->sc_cmd): "memory"); 523 524 /* Ring doorbell. */ 525 bus_space_write_1(sc->sc_memt, sc->sc_gpioh, 0, GPIO_DDR_OUTPUT); 526 527 do { 528 error = tsleep_nsec(sc, PWAIT, "smu", MSEC_TO_NSEC(msecs)); 529 if (error) 530 return (error); 531 gpio = bus_space_read_1(sc->sc_memt, sc->sc_gpioh, 0); 532 } while (!(gpio & (GPIO_DATA))); 533 534 /* CPU might have brought back the cache line. */ 535 asm volatile ("dcbf 0,%0; sync" :: "r"(sc->sc_cmd) : "memory"); 536 537 if (cmd->cmd != ack) 538 return (EIO); 539 return (0); 540} 541 542int 543smu_time_read(time_t *secs) 544{ 545 struct smu_softc *sc = smu_cd.cd_devs[0]; 546 struct smu_cmd *cmd = (struct smu_cmd *)sc->sc_cmd; 547 struct clock_ymdhms dt; 548 int error; 549 550 rw_enter_write(&sc->sc_lock); 551 552 cmd->cmd = SMU_RTC; 553 cmd->len = 1; 554 cmd->data[0] = SMU_RTC_GET_DATETIME; 555 error = smu_do_cmd(sc, 800); 556 if (error) { 557 rw_exit_write(&sc->sc_lock); 558 559 *secs = 0; 560 return (error); 561 } 562 563 dt.dt_year = 2000 + FROMBCD(cmd->data[6]); 564 dt.dt_mon = FROMBCD(cmd->data[5]); 565 dt.dt_day = FROMBCD(cmd->data[4]); 566 dt.dt_hour = FROMBCD(cmd->data[2]); 567 dt.dt_min = FROMBCD(cmd->data[1]); 568 dt.dt_sec = FROMBCD(cmd->data[0]); 569 570 rw_exit_write(&sc->sc_lock); 571 572 *secs = clock_ymdhms_to_secs(&dt); 573 return (0); 574} 575 576int 577smu_time_write(time_t secs) 578{ 579 struct smu_softc *sc = smu_cd.cd_devs[0]; 580 struct smu_cmd *cmd = (struct smu_cmd *)sc->sc_cmd; 581 struct clock_ymdhms dt; 582 int error; 583 584 clock_secs_to_ymdhms(secs, &dt); 585 586 rw_enter_write(&sc->sc_lock); 587 588 cmd->cmd = SMU_RTC; 589 cmd->len = 8; 590 cmd->data[0] = SMU_RTC_SET_DATETIME; 591 cmd->data[1] = TOBCD(dt.dt_sec); 592 cmd->data[2] = TOBCD(dt.dt_min); 593 cmd->data[3] = TOBCD(dt.dt_hour); 594 cmd->data[4] = TOBCD(dt.dt_wday); 595 cmd->data[5] = TOBCD(dt.dt_day); 596 cmd->data[6] = TOBCD(dt.dt_mon); 597 cmd->data[7] = TOBCD(dt.dt_year - 2000); 598 error = smu_do_cmd(sc, 800); 599 600 rw_exit_write(&sc->sc_lock); 601 602 return (error); 603} 604 605 606int 607smu_get_datablock(struct smu_softc *sc, u_int8_t id, u_int8_t *buf, size_t len) 608{ 609 struct smu_cmd *cmd = (struct smu_cmd *)sc->sc_cmd; 610 u_int8_t addr[4]; 611 int error; 612 613 cmd->cmd = SMU_PARTITION; 614 cmd->len = 2; 615 cmd->data[0] = SMU_PARTITION_LATEST; 616 cmd->data[1] = id; 617 error = smu_do_cmd(sc, 800); 618 if (error) 619 return (error); 620 621 addr[0] = 0x00; 622 addr[1] = 0x00; 623 addr[2] = cmd->data[0]; 624 addr[3] = cmd->data[1]; 625 626 cmd->cmd = SMU_MISC; 627 cmd->len = 7; 628 cmd->data[0] = SMU_MISC_GET_DATA; 629 cmd->data[1] = sizeof(u_int32_t); 630 cmd->data[2] = addr[0]; 631 cmd->data[3] = addr[1]; 632 cmd->data[4] = addr[2]; 633 cmd->data[5] = addr[3]; 634 cmd->data[6] = len; 635 error = smu_do_cmd(sc, 800); 636 if (error) 637 return (error); 638 639 memcpy(buf, cmd->data, len); 640 return (0); 641} 642 643void 644smu_firmware_probe(struct smu_softc *sc, struct smu_fan *fan) 645{ 646 struct smu_cmd *cmd = (struct smu_cmd *)sc->sc_cmd; 647 int error; 648 649 /* 650 * Find out if the smu runs an old or new firmware version 651 * by sending a new firmware command to read the fan speed. 652 * If it fails we assume to have an old firmware version. 653 */ 654 cmd->cmd = SMU_FAN; 655 cmd->len = 2; 656 cmd->data[0] = 0x31; 657 cmd->data[1] = fan->reg; 658 error = smu_do_cmd(sc, 800); 659 if (error) 660 sc->sc_firmware_old = 1; 661} 662 663int 664smu_fan_set_rpm(struct smu_softc *sc, struct smu_fan *fan, u_int16_t rpm) 665{ 666 struct smu_cmd *cmd = (struct smu_cmd *)sc->sc_cmd; 667 668 /* 669 * On the PowerMac8,2 this command expects the requested fan 670 * speed at a different location in the command block than on 671 * the PowerMac8,1. We simply store the value at both 672 * locations. 673 */ 674 if (sc->sc_firmware_old) { 675 cmd->cmd = SMU_FAN; 676 cmd->len = 14; 677 cmd->data[0] = 0x00; /* fan-rpm-control */ 678 cmd->data[1] = 0x01 << fan->reg; 679 cmd->data[2] = cmd->data[2 + fan->reg * 2] = (rpm >> 8) & 0xff; 680 cmd->data[3] = cmd->data[3 + fan->reg * 2] = (rpm & 0xff); 681 } else { 682 cmd->cmd = SMU_FAN; 683 cmd->len = 4; 684 cmd->data[0] = 0x30; 685 cmd->data[1] = fan->reg; 686 cmd->data[2] = (rpm >> 8) & 0xff; 687 cmd->data[3] = rpm & 0xff; 688 } 689 return smu_do_cmd(sc, 800); 690} 691 692int 693smu_fan_set_pwm(struct smu_softc *sc, struct smu_fan *fan, u_int16_t pwm) 694{ 695 struct smu_cmd *cmd = (struct smu_cmd *)sc->sc_cmd; 696 697 if (sc->sc_firmware_old) { 698 cmd->cmd = SMU_FAN; 699 cmd->len = 14; 700 cmd->data[0] = 0x10; /* fan-pwm-control */ 701 cmd->data[1] = 0x01 << fan->reg; 702 cmd->data[2] = cmd->data[2 + fan->reg * 2] = (pwm >> 8) & 0xff; 703 cmd->data[3] = cmd->data[3 + fan->reg * 2] = (pwm & 0xff); 704 } else { 705 cmd->cmd = SMU_FAN; 706 cmd->len = 4; 707 cmd->data[0] = 0x30; 708 cmd->data[1] = fan->reg; 709 cmd->data[2] = (pwm >> 8) & 0xff; 710 cmd->data[3] = pwm & 0xff; 711 } 712 return smu_do_cmd(sc, 800); 713} 714 715int 716smu_fan_read_rpm(struct smu_softc *sc, struct smu_fan *fan, u_int16_t *rpm) 717{ 718 struct smu_cmd *cmd = (struct smu_cmd *)sc->sc_cmd; 719 int error; 720 721 if (sc->sc_firmware_old) { 722 cmd->cmd = SMU_FAN; 723 cmd->len = 1; 724 cmd->data[0] = 0x01; /* fan-rpm-control */ 725 error = smu_do_cmd(sc, 800); 726 if (error) 727 return (error); 728 *rpm = (cmd->data[fan->reg * 2 + 1] << 8) | 729 cmd->data[fan->reg * 2 + 2]; 730 } else { 731 cmd->cmd = SMU_FAN; 732 cmd->len = 2; 733 cmd->data[0] = 0x31; 734 cmd->data[1] = fan->reg; 735 error = smu_do_cmd(sc, 800); 736 if (error) 737 return (error); 738 *rpm = (cmd->data[0] << 8) | cmd->data[1]; 739 } 740 741 return (0); 742} 743 744int 745smu_fan_read_pwm(struct smu_softc *sc, struct smu_fan *fan, u_int16_t *pwm, 746 u_int16_t *rpm) 747{ 748 struct smu_cmd *cmd = (struct smu_cmd *)sc->sc_cmd; 749 int error; 750 751 if (sc->sc_firmware_old) { 752 /* read PWM value */ 753 cmd->cmd = SMU_FAN; 754 cmd->len = 14; 755 cmd->data[0] = 0x12; 756 cmd->data[1] = 0x01 << fan->reg; 757 error = smu_do_cmd(sc, 800); 758 if (error) 759 return (error); 760 *pwm = cmd->data[fan->reg * 2 + 2]; 761 762 /* read RPM value */ 763 cmd->cmd = SMU_FAN; 764 cmd->len = 1; 765 cmd->data[0] = 0x11; 766 error = smu_do_cmd(sc, 800); 767 if (error) 768 return (error); 769 *rpm = (cmd->data[fan->reg * 2 + 1] << 8) | 770 cmd->data[fan->reg * 2 + 2]; 771 } else { 772 cmd->cmd = SMU_FAN; 773 cmd->len = 2; 774 cmd->data[0] = 0x31; 775 cmd->data[1] = fan->reg; 776 error = smu_do_cmd(sc, 800); 777 if (error) 778 return (error); 779 *rpm = (cmd->data[0] << 8) | cmd->data[1]; 780 781 /* XXX 782 * We don't know currently if there is a pwm read command 783 * for the new firmware as well. Therefore lets calculate 784 * the pwm value for now based on the rpm. 785 */ 786 *pwm = *rpm * 100 / fan->max_rpm; 787 } 788 789 return (0); 790} 791 792int 793smu_fan_refresh(struct smu_softc *sc, struct smu_fan *fan) 794{ 795 int error; 796 u_int16_t rpm, pwm; 797 798 if (fan->sensor.type == SENSOR_PERCENT) { 799 error = smu_fan_read_pwm(sc, fan, &pwm, &rpm); 800 if (error) { 801 fan->sensor.flags = SENSOR_FINVALID; 802 return (error); 803 } 804 fan->sensor.value = pwm * 1000; 805 fan->sensor.flags = 0; 806 } else { 807 error = smu_fan_read_rpm(sc, fan, &rpm); 808 if (error) { 809 fan->sensor.flags = SENSOR_FINVALID; 810 return (error); 811 } 812 fan->sensor.value = rpm; 813 fan->sensor.flags = 0; 814 } 815 816 return (0); 817} 818 819int 820smu_sensor_refresh(struct smu_softc *sc, struct smu_sensor *sensor, 821 int update_sysctl) 822{ 823 struct smu_cmd *cmd = (struct smu_cmd *)sc->sc_cmd; 824 int64_t value; 825 int error; 826 827 cmd->cmd = SMU_ADC; 828 cmd->len = 1; 829 cmd->data[0] = sensor->reg; 830 error = smu_do_cmd(sc, 800); 831 if (error) { 832 sensor->sensor.flags = SENSOR_FINVALID; 833 return (error); 834 } 835 value = (cmd->data[0] << 8) + cmd->data[1]; 836 switch (sensor->sensor.type) { 837 case SENSOR_TEMP: 838 value *= sc->sc_cpu_diode_scale; 839 value >>= 3; 840 value += ((int64_t)sc->sc_cpu_diode_offset) << 9; 841 value <<= 1; 842 843 /* Convert from 16.16 fixed point degC into muK. */ 844 value *= 15625; 845 value /= 1024; 846 value += 273150000; 847 break; 848 849 case SENSOR_VOLTS_DC: 850 value *= sc->sc_cpu_volt_scale; 851 value += sc->sc_cpu_volt_offset; 852 value <<= 4; 853 854 /* Convert from 16.16 fixed point V into muV. */ 855 value *= 15625; 856 value /= 1024; 857 break; 858 859 case SENSOR_AMPS: 860 value *= sc->sc_cpu_curr_scale; 861 value += sc->sc_cpu_curr_offset; 862 value <<= 4; 863 864 /* Convert from 16.16 fixed point A into muA. */ 865 value *= 15625; 866 value /= 1024; 867 break; 868 869 case SENSOR_WATTS: 870 value *= sc->sc_slots_pow_scale; 871 value += sc->sc_slots_pow_offset; 872 value <<= 4; 873 874 /* Convert from 16.16 fixed point W into muW. */ 875 value *= 15625; 876 value /= 1024; 877 break; 878 879 default: 880 break; 881 } 882 if (update_sysctl) { 883 sensor->sensor.value = value; 884 sensor->sensor.flags = 0; 885 } 886 return (value); 887} 888 889void 890smu_refresh_sensors(void *arg) 891{ 892 struct smu_softc *sc = arg; 893 int i; 894 895 rw_enter_write(&sc->sc_lock); 896 for (i = 0; i < sc->sc_num_sensors; i++) 897 smu_sensor_refresh(sc, &sc->sc_sensors[i], 1); 898 for (i = 0; i < sc->sc_num_fans; i++) 899 smu_fan_refresh(sc, &sc->sc_fans[i]); 900 rw_exit_write(&sc->sc_lock); 901} 902 903/* 904 * Wrapper functions for the thermal management framework. 905 */ 906int 907smu_fan_set_rpm_thermal(struct smu_fan *fan, int rpm) 908{ 909 struct smu_softc *sc = smu_cd.cd_devs[0]; 910 911 rw_enter_write(&sc->sc_lock); 912 (void)smu_fan_set_rpm(sc, fan, rpm); 913 rw_exit_write(&sc->sc_lock); 914 915 return (0); 916} 917 918int 919smu_fan_set_pwm_thermal(struct smu_fan *fan, int pwm) 920{ 921 struct smu_softc *sc = smu_cd.cd_devs[0]; 922 923 rw_enter_write(&sc->sc_lock); 924 (void)smu_fan_set_pwm(sc, fan, pwm); 925 rw_exit_write(&sc->sc_lock); 926 927 return (0); 928} 929 930int 931smu_sensor_refresh_thermal(struct smu_sensor *sensor) 932{ 933 struct smu_softc *sc = smu_cd.cd_devs[0]; 934 int value; 935 936 rw_enter_write(&sc->sc_lock); 937 value = smu_sensor_refresh(sc, sensor, 0); 938 rw_exit_write(&sc->sc_lock); 939 940 return (value); 941} 942 943int 944smu_i2c_acquire_bus(void *cookie, int flags) 945{ 946 struct smu_softc *sc = cookie; 947 948 if (flags & I2C_F_POLL) 949 return (0); 950 951 return (rw_enter(&sc->sc_lock, RW_WRITE)); 952} 953 954void 955smu_i2c_release_bus(void *cookie, int flags) 956{ 957 struct smu_softc *sc = cookie; 958 959 if (flags & I2C_F_POLL) 960 return; 961 962 rw_exit(&sc->sc_lock); 963} 964 965int 966smu_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, 967 const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags) 968{ 969 struct smu_softc *sc = cookie; 970 struct smu_cmd *cmd = (struct smu_cmd *)sc->sc_cmd; 971 u_int8_t smu_op = SMU_I2C_NORMAL; 972 int error, retries = 10; 973 974 if (!I2C_OP_STOP_P(op) || cmdlen > 3 || len > 5) 975 return (EINVAL); 976 977 if(cmdlen == 0) 978 smu_op = SMU_I2C_SIMPLE; 979 else if (I2C_OP_READ_P(op)) 980 smu_op = SMU_I2C_COMBINED; 981 982 cmd->cmd = SMU_I2C; 983 cmd->len = 9 + len; 984 cmd->data[0] = 0xb; 985 cmd->data[1] = smu_op; 986 cmd->data[2] = addr << 1; 987 cmd->data[3] = cmdlen; 988 memcpy (&cmd->data[4], cmdbuf, cmdlen); 989 cmd->data[7] = addr << 1 | I2C_OP_READ_P(op); 990 cmd->data[8] = len; 991 memcpy(&cmd->data[9], buf, len); 992 993 error = smu_do_cmd(sc, 250); 994 if (error) 995 return error; 996 997 while (retries--) { 998 cmd->cmd = SMU_I2C; 999 cmd->len = 1; 1000 cmd->data[0] = 0; 1001 memset(&cmd->data[1], 0xff, len); 1002 1003 error = smu_do_cmd(sc, 250); 1004 if (error) 1005 return error; 1006 1007 if ((cmd->data[0] & 0x80) == 0) 1008 break; 1009 if (cmd->data[0] == 0xfd) 1010 break; 1011 1012 DELAY(15 * 1000); 1013 } 1014 1015 if (cmd->data[0] & 0x80) 1016 return (EIO); 1017 1018 if (I2C_OP_READ_P(op)) 1019 memcpy(buf, &cmd->data[1], len); 1020 return (0); 1021} 1022 1023void 1024smu_slew_voltage(u_int freq_scale) 1025{ 1026 struct smu_softc *sc = smu_cd.cd_devs[0]; 1027 struct smu_cmd *cmd = (struct smu_cmd *)sc->sc_cmd; 1028 1029 rw_enter_write(&sc->sc_lock); 1030 1031 cmd->cmd = SMU_POWER; 1032 cmd->len = 8; 1033 memcpy(cmd->data, "VSLEW", 5); 1034 cmd->data[5] = 0xff; 1035 cmd->data[6] = 1; 1036 cmd->data[7] = freq_scale; 1037 1038 smu_do_cmd(sc, 250); 1039 1040 rw_exit_write(&sc->sc_lock); 1041} 1042