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