Home | History | Annotate | Line # | Download | only in dev
      1 /*-
      2  * Copyright (c) 2013 Phileas Fogg
      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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     15  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     16  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     18  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     24  * POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 #include <sys/param.h>
     28 #include <sys/systm.h>
     29 #include <sys/kernel.h>
     30 #include <sys/malloc.h>
     31 #include <sys/device.h>
     32 #include <sys/proc.h>
     33 #include <sys/mutex.h>
     34 #include <sys/time.h>
     35 #include <sys/reboot.h>
     36 #include <sys/sysctl.h>
     37 #include <sys/kthread.h>
     38 
     39 #include <machine/autoconf.h>
     40 
     41 #include <dev/ofw/openfirm.h>
     42 #include <dev/i2c/i2cvar.h>
     43 #include <dev/clock_subr.h>
     44 #include <dev/sysmon/sysmonvar.h>
     45 #include <dev/sysmon/sysmon_taskq.h>
     46 
     47 #include <macppc/dev/obiovar.h>
     48 #include <macppc/dev/smuvar.h>
     49 #include <macppc/dev/fancontrolvar.h>
     50 
     51 #include "opt_smu.h"
     52 
     53 struct smu_softc;
     54 
     55 struct smu_cmd {
     56 	u_char cmd;
     57 	u_char len;
     58 	u_char data[254];
     59 };
     60 
     61 struct smu_fan {
     62 	struct smu_softc* sc;
     63 
     64 	char location[32];
     65 	int reg;
     66 	int zone;
     67 	int rpm_ctl;
     68 	int min_rpm;
     69 	int max_rpm;
     70 	int default_rpm;
     71 	int wanted_rpm;
     72 	int current_rpm;
     73 	int fault;
     74 	time_t last_update;
     75 };
     76 
     77 struct smu_iicbus {
     78 	struct smu_softc* sc;
     79 
     80 	int reg;
     81 	struct i2c_controller i2c;
     82 };
     83 
     84 #define SMU_MAX_FANS		8
     85 #define SMU_MAX_IICBUS		3
     86 #define SMU_MAX_SME_SENSORS	(SMU_MAX_FANS + 8)
     87 
     88 
     89 #define SMU_ZONE_CPU		0
     90 #define SMU_ZONE_CASE		1
     91 #define SMU_ZONE_DRIVEBAY	2
     92 #define SMU_ZONES		3
     93 
     94 #define C_TO_uK(n) (n * 1000000 + 273150000)
     95 
     96 struct smu_softc {
     97 	device_t sc_dev;
     98 	int sc_node;
     99 	struct sysctlnode *sc_sysctl_me;
    100 
    101 	kmutex_t sc_cmd_lock;
    102 	kmutex_t sc_msg_lock;
    103 	struct smu_cmd *sc_cmd;
    104 	paddr_t sc_cmd_paddr;
    105 	int sc_dbell_mbox;
    106 	int sc_dbell_gpio;
    107 
    108 	int sc_num_fans;
    109 	struct smu_fan sc_fans[SMU_MAX_FANS];
    110 
    111 	int sc_num_iicbus;
    112 	struct smu_iicbus sc_iicbus[SMU_MAX_IICBUS];
    113 
    114 	struct todr_chip_handle sc_todr;
    115 
    116 	struct sysmon_envsys *sc_sme;
    117 	envsys_data_t sc_sme_sensors[SMU_MAX_SME_SENSORS];
    118 	uint32_t cpu_m;
    119 	int32_t  cpu_b;
    120 
    121 	fancontrol_zone_t sc_zones[SMU_ZONES];
    122 	lwp_t *sc_thread;
    123 	bool sc_dying;
    124 };
    125 
    126 #define SMU_CMD_FAN	0x4a
    127 #define SMU_CMD_RTC	0x8e
    128 #define SMU_CMD_I2C	0x9a
    129 #define SMU_CMD_POWER	0xaa
    130 #define SMU_CMD_ADC	0xd8
    131 #define SMU_MISC	0xee
    132 #define  SMU_MISC_GET_DATA	0x02
    133 #define  SMU_MISC_LED_CTRL	0x04
    134 
    135 #define SMU_CPUTEMP_CAL 0x18
    136 #define SMU_CPUVOLT_CAL	0x21
    137 #define SMU_SLOTPW_CAL	0x78
    138 
    139 #define SMU_PARTITION		0x3e
    140 #define SMU_PARTITION_LATEST	0x01
    141 #define SMU_PARTITION_BASE	0x02
    142 #define SMU_PARTITION_UPDATE	0x03
    143 
    144 #ifdef SMU_DEBUG
    145 #define DPRINTF printf
    146 #else
    147 #define DPRINTF while (0) printf
    148 #endif
    149 
    150 static int smu_match(device_t, struct cfdata *, void *);
    151 static void smu_attach(device_t, device_t, void *);
    152 static int smu_setup_doorbell(struct smu_softc *);
    153 static void smu_setup_fans(struct smu_softc *);
    154 static void smu_setup_iicbus(struct smu_softc *);
    155 static void smu_setup_sme(struct smu_softc *);
    156 static int smu_iicbus_print(void *, const char *);
    157 static void smu_sme_refresh(struct sysmon_envsys *, envsys_data_t *);
    158 static int smu_do_cmd(struct smu_softc *, struct smu_cmd *, int);
    159 static int smu_dbell_gpio_intr(void *);
    160 static int smu_todr_gettime_ymdhms(todr_chip_handle_t, struct clock_ymdhms *);
    161 static int smu_todr_settime_ymdhms(todr_chip_handle_t, struct clock_ymdhms *);
    162 static int smu_fan_update_rpm(struct smu_fan *);
    163 static int smu_read_adc(struct smu_softc *, int);
    164 
    165 static int smu_iicbus_exec(void *, i2c_op_t, i2c_addr_t, const void *,
    166     size_t, void *, size_t, int);
    167 
    168 static void smu_setup_zones(struct smu_softc *);
    169 static void smu_adjust(void *);
    170 
    171 static bool is_cpu_sensor(const envsys_data_t *);
    172 static bool is_drive_sensor(const envsys_data_t *);
    173 static bool is_slots_sensor(const envsys_data_t *);
    174 static int smu_fan_get_rpm(void *, int);
    175 static int smu_fan_set_rpm(void *, int, int);
    176 
    177 int smu_get_datablock(int, uint8_t *, size_t);
    178 
    179 CFATTACH_DECL_NEW(smu, sizeof(struct smu_softc),
    180     smu_match, smu_attach, NULL, NULL);
    181 
    182 static struct smu_softc *smu0 = NULL;
    183 
    184 static int
    185 smu_match(device_t parent, struct cfdata *cf, void *aux)
    186 {
    187 	struct confargs *ca = aux;
    188 
    189 	if (strcmp(ca->ca_name, "smu") == 0)
    190 		return 5;
    191 
    192 	return 0;
    193 }
    194 
    195 static void
    196 smu_attach(device_t parent, device_t self, void *aux)
    197 {
    198 	struct confargs *ca = aux;
    199 	struct smu_softc *sc = device_private(self);
    200 	uint16_t data[4];
    201 
    202 	sc->sc_dev = self;
    203 	sc->sc_node = ca->ca_node;
    204 
    205 	if (smu0 == NULL)
    206 		smu0 = sc;
    207 
    208 	sysctl_createv(NULL, 0, NULL, (void *) &sc->sc_sysctl_me,
    209 	    CTLFLAG_READWRITE,
    210 	    CTLTYPE_NODE, device_xname(sc->sc_dev), NULL,
    211 	    NULL, 0, NULL, 0,
    212 	    CTL_MACHDEP, CTL_CREATE, CTL_EOL);
    213 
    214 	if (smu_setup_doorbell(sc) != 0) {
    215 		aprint_normal(": unable to set up doorbell\n");
    216 		return;
    217 	}
    218 
    219 	aprint_normal("\n");
    220 
    221 	smu_setup_fans(sc);
    222 	smu_setup_iicbus(sc);
    223 
    224 	sc->sc_todr.todr_gettime_ymdhms = smu_todr_gettime_ymdhms;
    225 	sc->sc_todr.todr_settime_ymdhms = smu_todr_settime_ymdhms;
    226 	sc->sc_todr.todr_dev = self;
    227 	todr_attach(&sc->sc_todr);
    228 
    229 	/* calibration data */
    230 	memset(data, 0, 8);
    231 	smu_get_datablock(SMU_CPUTEMP_CAL, (void *)data, 8);
    232 	DPRINTF("data %04x %04x %04x %04x\n", data[0], data[1], data[2], data[3]);
    233 	sc->cpu_m = data[2];
    234 	sc->cpu_b = (int16_t)data[3];
    235 
    236 	smu_setup_sme(sc);
    237 
    238 	smu_setup_zones(sc);
    239 }
    240 
    241 static int
    242 smu_setup_doorbell(struct smu_softc *sc)
    243 {
    244 	int node, parent, reg[4], gpio_base, irq;
    245 
    246 	mutex_init(&sc->sc_cmd_lock, MUTEX_DEFAULT, IPL_NONE);
    247 	sc->sc_cmd = malloc(4096, M_DEVBUF, M_WAITOK);
    248 	sc->sc_cmd_paddr = vtophys((vaddr_t) sc->sc_cmd);
    249 
    250 	DPRINTF("%s: cmd vaddr 0x%x paddr 0x%x\n",
    251 	    __func__, (unsigned int) sc->sc_cmd,
    252 	    (unsigned int) sc->sc_cmd_paddr);
    253 
    254 	if (OF_getprop(sc->sc_node, "platform-doorbell-buff",
    255 	        &node, sizeof(node)) <= 0)
    256 		return -1;
    257 
    258 	if (OF_getprop(node, "platform-do-doorbell-buff",
    259 	        reg, sizeof(reg)) < sizeof(reg))
    260 		return -1;
    261 
    262 	sc->sc_dbell_mbox = reg[3];
    263 
    264 	if (OF_getprop(sc->sc_node, "platform-doorbell-ack",
    265 	        &node, sizeof(node)) <= 0)
    266 		return -1;
    267 
    268 	parent = OF_parent(node);
    269 	if (parent == 0)
    270 		return -1;
    271 
    272 	if (OF_getprop(parent, "reg", &gpio_base, sizeof(gpio_base)) <= 0)
    273 		return -1;
    274 
    275 	if (OF_getprop(node, "reg", reg, sizeof(reg)) <= 0)
    276 		return -1;
    277 
    278 	if (OF_getprop(node, "interrupts", &irq, sizeof(irq)) <= 0)
    279 		return -1;
    280 
    281 	sc->sc_dbell_gpio = gpio_base + reg[0];
    282 
    283 	aprint_normal(" mbox 0x%x gpio 0x%x irq %d",
    284 	    sc->sc_dbell_mbox, sc->sc_dbell_gpio, irq);
    285 
    286 	intr_establish_xname(irq, IST_EDGE_FALLING, IPL_TTY,
    287 	    smu_dbell_gpio_intr, sc, device_xname(sc->sc_dev));
    288 
    289 	return 0;
    290 }
    291 
    292 static void
    293 smu_setup_fans(struct smu_softc *sc)
    294 {
    295 	struct smu_fan *fan;
    296 	char type[32];
    297 	int node, i;
    298 	const char *fans[] = { "fans", "rpm-fans", 0 };
    299 	int n = 0;
    300 
    301 	while (fans[n][0] != 0) {
    302 		node = of_getnode_byname(sc->sc_node, fans[n]);
    303 		for (node = OF_child(node);
    304 		    (node != 0) && (sc->sc_num_fans < SMU_MAX_FANS);
    305 		    node = OF_peer(node)) {
    306 			fan = &sc->sc_fans[sc->sc_num_fans];
    307 			fan->sc = sc;
    308 
    309 			memset(fan->location, 0, sizeof(fan->location));
    310 			OF_getprop(node, "location", fan->location,
    311 			    sizeof(fan->location));
    312 
    313 			if (OF_getprop(node, "reg", &fan->reg,
    314 			        sizeof(fan->reg)) <= 0)
    315 				continue;
    316 
    317 			if (OF_getprop(node, "zone", &fan->zone	,
    318 			        sizeof(fan->zone)) <= 0)
    319 				continue;
    320 
    321 			memset(type, 0, sizeof(type));
    322 			OF_getprop(node, "device_type", type, sizeof(type));
    323 			if (strcmp(type, "fan-rpm-control") == 0)
    324 				fan->rpm_ctl = 1;
    325 			else
    326 				fan->rpm_ctl = 0;
    327 
    328 			if (OF_getprop(node, "min-value", &fan->min_rpm,
    329 			    sizeof(fan->min_rpm)) <= 0)
    330 				fan->min_rpm = 0;
    331 
    332 			if (OF_getprop(node, "max-value", &fan->max_rpm,
    333 			    sizeof(fan->max_rpm)) <= 0)
    334 				fan->max_rpm = 0xffff;
    335 
    336 			if (OF_getprop(node, "unmanage-value", &fan->default_rpm,
    337 			    sizeof(fan->default_rpm)) <= 0)
    338 				fan->default_rpm = fan->max_rpm;
    339 
    340 			DPRINTF("fan: location %s reg %x zone %d rpm_ctl %d "
    341 			    "min_rpm %d max_rpm %d default_rpm %d\n",
    342 			    fan->location, fan->reg, fan->zone, fan->rpm_ctl,
    343 			    fan->min_rpm, fan->max_rpm, fan->default_rpm);
    344 
    345 			fan->wanted_rpm = fan->default_rpm;
    346 			fan->fault = 0;
    347 			sc->sc_num_fans++;
    348 		}
    349 		n++;
    350 	}
    351 
    352 	for (i = 0; i < sc->sc_num_fans; i++) {
    353 		fan = &sc->sc_fans[i];
    354 		smu_fan_set_rpm(sc, i, fan->default_rpm);
    355 		smu_fan_update_rpm(fan);
    356 	}
    357 }
    358 
    359 static void
    360 smu_setup_iicbus(struct smu_softc *sc)
    361 {
    362 	struct smu_iicbus *iicbus;
    363 	struct i2c_controller *i2c;
    364 	struct smu_iicbus_confargs ca;
    365 	int node;
    366 	char name[32];
    367 
    368 	devhandle_t selfh = device_handle(sc->sc_dev);
    369 	node = of_getnode_byname(sc->sc_node, "smu-i2c-control");
    370 	if (node == 0) node = sc->sc_node;
    371 	for (node = OF_child(node);
    372 	    (node != 0) && (sc->sc_num_iicbus < SMU_MAX_IICBUS);
    373 	    node = OF_peer(node)) {
    374 		memset(name, 0, sizeof(name));
    375 		OF_getprop(node, "name", name, sizeof(name));
    376 		if ((strcmp(name, "i2c-bus") != 0) &&
    377 		    (strcmp(name, "i2c") != 0))
    378 			continue;
    379 
    380 		iicbus = &sc->sc_iicbus[sc->sc_num_iicbus];
    381 		iicbus->sc = sc;
    382 		i2c = &iicbus->i2c;
    383 
    384 		if (OF_getprop(node, "reg", &iicbus->reg, sizeof(iicbus->reg)) <= 0)
    385 			continue;
    386 
    387 		DPRINTF("iicbus: reg %x\n", iicbus->reg);
    388 
    389 		iic_tag_init(i2c);
    390 		i2c->ic_cookie = iicbus;
    391 		i2c->ic_exec = smu_iicbus_exec;
    392 
    393 		ca.ca_name = name;
    394 		ca.ca_node = node;
    395 		ca.ca_tag = i2c;
    396 		config_found(sc->sc_dev, &ca, smu_iicbus_print,
    397 		    CFARGS(.devhandle = devhandle_from_of(selfh, node)));
    398 
    399 		sc->sc_num_iicbus++;
    400 	}
    401 }
    402 
    403 static void
    404 smu_setup_sme(struct smu_softc *sc)
    405 {
    406 	struct smu_fan *fan;
    407 	envsys_data_t *sme_sensor;
    408 	int i, sensors, child, reg;
    409 	char loc[32], type[32];
    410 
    411 	sc->sc_sme = sysmon_envsys_create();
    412 
    413 	for (i = 0; i < sc->sc_num_fans; i++) {
    414 		sme_sensor = &sc->sc_sme_sensors[i];
    415 		fan = &sc->sc_fans[i];
    416 
    417 		sme_sensor->units = ENVSYS_SFANRPM;
    418 		sme_sensor->state = ENVSYS_SINVALID;
    419 		snprintf(sme_sensor->desc, sizeof(sme_sensor->desc),
    420 		    "%s", fan->location);
    421 
    422 		if (sysmon_envsys_sensor_attach(sc->sc_sme, sme_sensor)) {
    423 			sysmon_envsys_destroy(sc->sc_sme);
    424 			return;
    425 		}
    426 	}
    427 	sensors = OF_finddevice("/smu/sensors");
    428 	child = OF_child(sensors);
    429 	while (child != 0) {
    430 		sme_sensor = &sc->sc_sme_sensors[i];
    431 		if (OF_getprop(child, "location", loc, 32) == 0) goto next;
    432 		if (OF_getprop(child, "device_type", type, 32) == 0) goto next;
    433 		if (OF_getprop(child, "reg", &reg, 4) == 0) goto next;
    434 		if (strcmp(type, "temp-sensor") == 0) {
    435 			sme_sensor->units = ENVSYS_STEMP;
    436 			sme_sensor->state = ENVSYS_SINVALID;
    437 			strncpy(sme_sensor->desc, loc, sizeof(sme_sensor->desc));
    438 			sme_sensor->private = reg;
    439 			sysmon_envsys_sensor_attach(sc->sc_sme, sme_sensor);
    440 			i++;
    441 			printf("%s: %s@%x\n", loc, type, reg);
    442 		}
    443 next:
    444 		child = OF_peer(child);
    445 	}
    446 
    447 	sc->sc_sme->sme_name = device_xname(sc->sc_dev);
    448 	sc->sc_sme->sme_cookie = sc;
    449 	sc->sc_sme->sme_refresh = smu_sme_refresh;
    450 
    451 	if (sysmon_envsys_register(sc->sc_sme)) {
    452 		aprint_error_dev(sc->sc_dev,
    453 		    "unable to register with sysmon\n");
    454 		sysmon_envsys_destroy(sc->sc_sme);
    455 	}
    456 }
    457 
    458 static int
    459 smu_iicbus_print(void *aux, const char *smu)
    460 {
    461 	struct smu_iicbus_confargs *ca = aux;
    462 
    463 	if (smu)
    464 		aprint_normal("%s at %s", ca->ca_name, smu);
    465 
    466 	return UNCONF;
    467 }
    468 
    469 static void
    470 smu_sme_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
    471 {
    472 	struct smu_softc *sc = sme->sme_cookie;
    473 	int which = edata->sensor;
    474 	int ret;
    475 
    476 	edata->state = ENVSYS_SINVALID;
    477 
    478 	if (which < sc->sc_num_fans) {
    479 
    480 		ret = smu_fan_get_rpm(sc, which);
    481 		if (ret != -1) {
    482 			sc->sc_fans[which].current_rpm = ret;
    483 			edata->value_cur = ret;
    484 			edata->state = ENVSYS_SVALID;
    485 		}
    486 	} else if (edata->private > 0) {
    487 		/* this works only for the CPU diode */
    488 		int64_t r = smu_read_adc(sc, edata->private);
    489 		if (r != -1) {
    490 			r = r * sc->cpu_m;
    491 			r >>= 3;
    492 			r += (int64_t)sc->cpu_b << 9;
    493 			r <<= 1;
    494 			r *= 15625;
    495 			r /= 1024;
    496 			edata->value_cur = r + 273150000;
    497 			edata->state = ENVSYS_SVALID;
    498 		}
    499 	}
    500 }
    501 
    502 static int
    503 smu_do_cmd(struct smu_softc *sc, struct smu_cmd *cmd, int timo)
    504 {
    505 	int gpio, ret, bail;
    506 	u_char ack;
    507 
    508 	mutex_enter(&sc->sc_cmd_lock);
    509 
    510 	DPRINTF("%s: cmd %02x len %02x\n", __func__, cmd->cmd, cmd->len);
    511 	DPRINTF("%s: data %02x %02x %02x %02x %02x %02x %02x %02x\n", __func__,
    512 	    cmd->data[0], cmd->data[1], cmd->data[2], cmd->data[3],
    513 	    cmd->data[4], cmd->data[5], cmd->data[6], cmd->data[7]);
    514 
    515 	sc->sc_cmd->cmd = cmd->cmd;
    516 	sc->sc_cmd->len = cmd->len;
    517 	memcpy(sc->sc_cmd->data, cmd->data, cmd->len);
    518 
    519 	__asm volatile ("dcbf 0,%0; sync" :: "r"(sc->sc_cmd) : "memory");
    520 
    521 	obio_write_4(sc->sc_dbell_mbox, sc->sc_cmd_paddr);
    522 	obio_write_1(sc->sc_dbell_gpio, 0x04);
    523 
    524 	bail = 0;
    525 
    526 	gpio = obio_read_1(sc->sc_dbell_gpio);
    527 
    528 	while (((gpio & 0x07) != 0x07) && (bail < timo)) {
    529 		ret = tsleep(sc->sc_cmd, PWAIT, "smu_cmd", mstohz(10));
    530 		if (ret != 0) {
    531 			bail++;
    532 		}
    533 		gpio = obio_read_1(sc->sc_dbell_gpio);
    534 	}
    535 
    536 	if ((gpio & 0x07) != 0x07) {
    537 		mutex_exit(&sc->sc_cmd_lock);
    538 		return EWOULDBLOCK;
    539 	}
    540 
    541 	__asm volatile ("dcbf 0,%0; sync" :: "r"(sc->sc_cmd) : "memory");
    542 
    543 	ack = (~cmd->cmd) & 0xff;
    544 	if (sc->sc_cmd->cmd != ack) {
    545 		DPRINTF("%s: invalid ack, got %x expected %x\n",
    546 		    __func__, sc->sc_cmd->cmd, ack);
    547 		mutex_exit(&sc->sc_cmd_lock);
    548 		return EIO;
    549 	}
    550 
    551 	cmd->cmd = sc->sc_cmd->cmd;
    552 	cmd->len = sc->sc_cmd->len;
    553 	memcpy(cmd->data, sc->sc_cmd->data, sc->sc_cmd->len);
    554 
    555 	mutex_exit(&sc->sc_cmd_lock);
    556 
    557 	return 0;
    558 }
    559 
    560 
    561 static int
    562 smu_dbell_gpio_intr(void *arg)
    563 {
    564 	struct smu_softc *sc = arg;
    565 
    566 	DPRINTF("%s\n", __func__);
    567 
    568 	wakeup(sc->sc_cmd);
    569 
    570 	return 1;
    571 }
    572 
    573 void
    574 smu_poweroff(void)
    575 {
    576 	struct smu_cmd cmd;
    577 
    578 	if (smu0 == NULL)
    579 		return;
    580 
    581 	cmd.cmd = SMU_CMD_POWER;
    582 	strcpy(cmd.data, "SHUTDOWN");
    583 	cmd.len = strlen(cmd.data) + 1;
    584 	smu_do_cmd(smu0, &cmd, 800);
    585 
    586 	for (;;);
    587 }
    588 
    589 void
    590 smu_restart(void)
    591 {
    592 	struct smu_cmd cmd;
    593 
    594 	if (smu0 == NULL)
    595 		return;
    596 
    597 	cmd.cmd = SMU_CMD_POWER;
    598 	strcpy(cmd.data, "RESTART");
    599 	cmd.len = strlen(cmd.data) + 1;
    600 	smu_do_cmd(smu0, &cmd, 800);
    601 
    602 	for (;;);
    603 }
    604 
    605 static int
    606 smu_todr_gettime_ymdhms(todr_chip_handle_t tch, struct clock_ymdhms *dt)
    607 {
    608 	struct smu_softc *sc = device_private(tch->todr_dev);
    609 	struct smu_cmd cmd;
    610 	int ret;
    611 
    612 	cmd.cmd = SMU_CMD_RTC;
    613 	cmd.len = 1;
    614 	cmd.data[0] = 0x81;
    615 
    616 	ret = smu_do_cmd(sc, &cmd, 800);
    617 	if (ret != 0)
    618 		return ret;
    619 
    620 	dt->dt_sec = bcdtobin(cmd.data[0]);
    621 	dt->dt_min = bcdtobin(cmd.data[1]);
    622 	dt->dt_hour = bcdtobin(cmd.data[2]);
    623 	dt->dt_wday = bcdtobin(cmd.data[3]);
    624 	dt->dt_day = bcdtobin(cmd.data[4]);
    625 	dt->dt_mon = bcdtobin(cmd.data[5]);
    626 	dt->dt_year = bcdtobin(cmd.data[6]) + 2000;
    627 
    628 	return 0;
    629 }
    630 
    631 static int
    632 smu_todr_settime_ymdhms(todr_chip_handle_t tch, struct clock_ymdhms *dt)
    633 {
    634 	struct smu_softc *sc = device_private(tch->todr_dev);
    635 	struct smu_cmd cmd;
    636 
    637 	cmd.cmd = SMU_CMD_RTC;
    638 	cmd.len = 8;
    639 	cmd.data[0] = 0x80;
    640 	cmd.data[1] = bintobcd(dt->dt_sec);
    641 	cmd.data[2] = bintobcd(dt->dt_min);
    642 	cmd.data[3] = bintobcd(dt->dt_hour);
    643 	cmd.data[4] = bintobcd(dt->dt_wday);
    644 	cmd.data[5] = bintobcd(dt->dt_day);
    645 	cmd.data[6] = bintobcd(dt->dt_mon);
    646 	cmd.data[7] = bintobcd(dt->dt_year - 2000);
    647 
    648 	return smu_do_cmd(sc, &cmd, 800);
    649 }
    650 
    651 static int
    652 smu_fan_update_rpm(struct smu_fan *fan)
    653 {
    654 	struct smu_softc *sc = fan->sc;
    655 	struct smu_cmd cmd;
    656 	int ret, diff;
    657 
    658 	cmd.cmd = SMU_CMD_FAN;
    659 	cmd.len = 2;
    660 	cmd.data[0] = 0x31;
    661 	cmd.data[1] = fan->reg;
    662 
    663 	ret = smu_do_cmd(sc, &cmd, 800);
    664 	if (ret == 0) {
    665 		fan->last_update = time_uptime;
    666 		fan->current_rpm = (cmd.data[0] << 8) | cmd.data[1];
    667 	} else {
    668 		cmd.cmd = SMU_CMD_FAN;
    669 		cmd.len = 1;
    670 		cmd.data[0] = 0x01;
    671 
    672 		ret = smu_do_cmd(sc, &cmd, 800);
    673 		if (ret == 0) {
    674 			fan->last_update = time_uptime;
    675 			fan->current_rpm = (cmd.data[1 + fan->reg * 2] << 8) |
    676 			    cmd.data[2 + fan->reg * 2];
    677 		}
    678 	}
    679 	diff = abs(fan->current_rpm - fan->wanted_rpm);
    680 	if (diff > fan->max_rpm >> 3) {
    681 		fan->fault++;
    682 	} else fan->fault = 0;
    683 	return ret;
    684 }
    685 
    686 static int
    687 smu_fan_get_rpm(void *cookie, int which)
    688 {
    689 	struct smu_softc *sc = cookie;
    690 	struct smu_fan *fan = &sc->sc_fans[which];
    691 	int ret;
    692 	ret = 0;
    693 
    694 	if (time_uptime - fan->last_update > 1) {
    695 		ret = smu_fan_update_rpm(fan);
    696 		if (ret != 0)
    697 			return -1;
    698 	}
    699 
    700 	return fan->current_rpm;
    701 }
    702 
    703 static int
    704 smu_fan_set_rpm(void *cookie, int which, int rpm)
    705 {
    706 	struct smu_softc *sc = cookie;
    707 	struct smu_fan *fan = &sc->sc_fans[which];
    708 	struct smu_cmd cmd;
    709 	int ret;
    710 
    711 	DPRINTF("%s: fan %s rpm %d\n", __func__, fan->location, rpm);
    712 
    713 	rpm = uimax(fan->min_rpm, rpm);
    714 	rpm = uimin(fan->max_rpm, rpm);
    715 
    716 	fan->wanted_rpm = rpm;
    717 
    718 	cmd.cmd = SMU_CMD_FAN;
    719 	cmd.len = 4;
    720 	cmd.data[0] = 0x30;
    721 	cmd.data[1] = fan->reg;
    722 	cmd.data[2] = (rpm >> 8) & 0xff;
    723 	cmd.data[3] = rpm & 0xff;
    724 
    725 	ret = smu_do_cmd(sc, &cmd, 800);
    726 	if (ret != 0) {
    727 		cmd.cmd = SMU_CMD_FAN;
    728 		cmd.len = 14;
    729 		cmd.data[0] = fan->rpm_ctl ? 0x00 : 0x10;
    730 		cmd.data[1] = 1 << fan->reg;
    731 		cmd.data[2] = cmd.data[2 + fan->reg * 2] = (rpm >> 8) & 0xff;
    732 		cmd.data[3] = cmd.data[3 + fan->reg * 2] = rpm & 0xff;
    733 
    734 		ret = smu_do_cmd(sc, &cmd, 800);
    735 	}
    736 
    737 	return ret;
    738 }
    739 
    740 static int
    741 smu_read_adc(struct smu_softc *sc, int id)
    742 {
    743 	struct smu_cmd cmd;
    744 	int ret;
    745 
    746 	cmd.cmd = SMU_CMD_ADC;
    747 	cmd.len = 1;
    748 	cmd.data[0] = id;
    749 
    750 	ret = smu_do_cmd(sc, &cmd, 800);
    751 	if (ret == 0) {
    752 		return cmd.data[0] << 8 | cmd.data[1];
    753 	}
    754 	return -1;
    755 }
    756 
    757 static int
    758 smu_iicbus_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *send,
    759     size_t send_len, void *recv, size_t recv_len, int flags)
    760 {
    761 	struct smu_iicbus *iicbus = cookie;
    762 	struct smu_softc *sc = iicbus->sc;
    763 	struct smu_cmd cmd;
    764 	int retries, ret;
    765 
    766 	DPRINTF("%s: op %x addr %x send_len %d recv_len %d\n",
    767 	    __func__, op, addr, send_len, recv_len);
    768 
    769 	cmd.cmd = SMU_CMD_I2C;
    770 	cmd.len = 9 + recv_len;
    771 	cmd.data[0] = iicbus->reg;
    772 	cmd.data[1] = I2C_OP_READ_P(op) ? 0x02 : 0x00;
    773 	cmd.data[2] = addr << 1;
    774 	cmd.data[3] = send_len;
    775 	memcpy(&cmd.data[4], send, send_len);
    776 	cmd.data[7] = addr << 1;
    777 	if (I2C_OP_READ_P(op))
    778 		cmd.data[7] |= 0x01;
    779 	cmd.data[8] = recv_len;
    780 	memcpy(&cmd.data[9], recv, recv_len);
    781 
    782 	ret = smu_do_cmd(sc, &cmd, 800);
    783 	if (ret != 0)
    784 		return (ret);
    785 
    786 	for (retries = 0; retries < 10; retries++) {
    787 		cmd.cmd = SMU_CMD_I2C;
    788 		cmd.len = 1;
    789 		cmd.data[0] = 0x00;
    790 		memset(&cmd.data[1], 0xff, recv_len);
    791 
    792 		ret = smu_do_cmd(sc, &cmd, 800);
    793 
    794 		DPRINTF("%s: cmd data[0] %x\n", __func__, cmd.data[0]);
    795 
    796 		if (ret == 0 && (cmd.data[0] & 0x80) == 0)
    797 			break;
    798 
    799 		DELAY(10000);
    800 	}
    801 
    802 	if (cmd.data[0] & 0x80)
    803 		return EIO;
    804 
    805 	if (I2C_OP_READ_P(op))
    806 		memcpy(recv, &cmd.data[1], recv_len);
    807 
    808 	return 0;
    809 }
    810 
    811 SYSCTL_SETUP(smu_sysctl_setup, "SMU sysctl subtree setup")
    812 {
    813 	sysctl_createv(NULL, 0, NULL, NULL,
    814 	    CTLFLAG_PERMANENT, CTLTYPE_NODE, "machdep", NULL,
    815 	    NULL, 0, NULL, 0, CTL_MACHDEP, CTL_EOL);
    816 }
    817 
    818 static void
    819 smu_setup_zones(struct smu_softc *sc)
    820 {
    821 	struct smu_fan *f;
    822 	fancontrol_zone_t *z;
    823 	int i;
    824 
    825 	/* init zones */
    826 	sc->sc_zones[SMU_ZONE_CPU].name = "CPUs";
    827 	sc->sc_zones[SMU_ZONE_CPU].filter = is_cpu_sensor;
    828 	sc->sc_zones[SMU_ZONE_CPU].cookie = sc;
    829 	sc->sc_zones[SMU_ZONE_CPU].get_rpm = smu_fan_get_rpm;
    830 	sc->sc_zones[SMU_ZONE_CPU].set_rpm = smu_fan_set_rpm;
    831 	sc->sc_zones[SMU_ZONE_CPU].Tmin = 45;
    832 	sc->sc_zones[SMU_ZONE_CPU].Tmax = 80;
    833 	sc->sc_zones[SMU_ZONE_CPU].nfans = 0;
    834 	sc->sc_zones[SMU_ZONE_CASE].name = "Slots";
    835 	sc->sc_zones[SMU_ZONE_CASE].filter = is_slots_sensor;
    836 	sc->sc_zones[SMU_ZONE_CASE].cookie = sc;
    837 	sc->sc_zones[SMU_ZONE_CASE].Tmin = 50;
    838 	sc->sc_zones[SMU_ZONE_CASE].Tmax = 75;
    839 	sc->sc_zones[SMU_ZONE_CASE].nfans = 0;
    840 	sc->sc_zones[SMU_ZONE_CASE].get_rpm = smu_fan_get_rpm;
    841 	sc->sc_zones[SMU_ZONE_CASE].set_rpm = smu_fan_set_rpm;
    842 	sc->sc_zones[SMU_ZONE_DRIVEBAY].name = "Drivebays";
    843 	sc->sc_zones[SMU_ZONE_DRIVEBAY].filter = is_drive_sensor;
    844 	sc->sc_zones[SMU_ZONE_DRIVEBAY].cookie = sc;
    845 	sc->sc_zones[SMU_ZONE_DRIVEBAY].get_rpm = smu_fan_get_rpm;
    846 	sc->sc_zones[SMU_ZONE_DRIVEBAY].set_rpm = smu_fan_set_rpm;
    847 	sc->sc_zones[SMU_ZONE_DRIVEBAY].Tmin = 30;
    848 	sc->sc_zones[SMU_ZONE_DRIVEBAY].Tmax = 50;
    849 	sc->sc_zones[SMU_ZONE_DRIVEBAY].nfans = 0;
    850 
    851 	/* find CPU fans */
    852 	z = &sc->sc_zones[SMU_ZONE_CPU];
    853 	for (i = 0; i < SMU_MAX_FANS; i++) {
    854 		f = &sc->sc_fans[i];
    855 		if ((strstr(f->location, "CPU") != NULL) ||
    856 		    (strstr(f->location, "System") != NULL)) {
    857 			z->fans[z->nfans].num = i;
    858 			z->fans[z->nfans].min_rpm = f->min_rpm;
    859 			z->fans[z->nfans].max_rpm = f->max_rpm;
    860 			z->fans[z->nfans].name = f->location;
    861 			z->nfans++;
    862 		}
    863 	}
    864 	aprint_normal_dev(sc->sc_dev,
    865 	    "using %d fans for CPU zone\n", z->nfans);
    866 
    867 	z = &sc->sc_zones[SMU_ZONE_DRIVEBAY];
    868 	for (i = 0; i < SMU_MAX_FANS; i++) {
    869 		f = &sc->sc_fans[i];
    870 		if ((strstr(f->location, "DRIVE") != NULL) ||
    871 		    (strstr(f->location, "Drive") != NULL)) {
    872 			z->fans[z->nfans].num = i;
    873 			z->fans[z->nfans].min_rpm = f->min_rpm;
    874 			z->fans[z->nfans].max_rpm = f->max_rpm;
    875 			z->fans[z->nfans].name = f->location;
    876 			z->nfans++;
    877 		}
    878 	}
    879 	aprint_normal_dev(sc->sc_dev,
    880 	    "using %d fans for drive bay zone\n", z->nfans);
    881 
    882 	z = &sc->sc_zones[SMU_ZONE_CASE];
    883 	for (i = 0; i < SMU_MAX_FANS; i++) {
    884 		f = &sc->sc_fans[i];
    885 		if ((strstr(f->location, "BACKSIDE") != NULL) ||
    886 		    (strstr(f->location, "SLOTS") != NULL)) {
    887 			z->fans[z->nfans].num = i;
    888 			z->fans[z->nfans].min_rpm = f->min_rpm;
    889 			z->fans[z->nfans].max_rpm = f->max_rpm;
    890 			z->fans[z->nfans].name = f->location;
    891 			z->nfans++;
    892 		}
    893 	}
    894 	aprint_normal_dev(sc->sc_dev,
    895 	    "using %d fans for expansion slots zone\n", z->nfans);
    896 
    897 	/* setup sysctls for our zones etc. */
    898 	for (i = 0; i < SMU_ZONES; i++) {
    899 		fancontrol_init_zone(&sc->sc_zones[i], sc->sc_sysctl_me);
    900 	}
    901 
    902 	sc->sc_dying = false;
    903 	kthread_create(PRI_NONE, 0, curcpu(), smu_adjust, sc, &sc->sc_thread,
    904 	    "fan control");
    905 }
    906 
    907 static void
    908 smu_adjust(void *cookie)
    909 {
    910 	struct smu_softc *sc = cookie;
    911 	int i;
    912 
    913 	while (!sc->sc_dying) {
    914 		for (i = 0; i < SMU_ZONES; i++)
    915 			if (sc->sc_zones[i].nfans > 0)
    916 				fancontrol_adjust_zone(&sc->sc_zones[i]);
    917 		kpause("fanctrl", true, mstohz(2000), NULL);
    918 	}
    919 	kthread_exit(0);
    920 }
    921 
    922 static bool is_cpu_sensor(const envsys_data_t *edata)
    923 {
    924 	if (edata->units != ENVSYS_STEMP)
    925 		return false;
    926 	if (strstr(edata->desc, "CPU") != NULL)
    927 		return TRUE;
    928 	return false;
    929 }
    930 
    931 static bool is_drive_sensor(const envsys_data_t *edata)
    932 {
    933 	if (edata->units != ENVSYS_STEMP)
    934 		return false;
    935 	if (strstr(edata->desc, "DRIVE") != NULL)
    936 		return TRUE;
    937 	if (strstr(edata->desc, "drive") != NULL)
    938 		return TRUE;
    939 	return false;
    940 }
    941 
    942 static bool is_slots_sensor(const envsys_data_t *edata)
    943 {
    944 	if (edata->units != ENVSYS_STEMP)
    945 		return false;
    946 	if (strstr(edata->desc, "BACKSIDE") != NULL)
    947 		return TRUE;
    948 	if (strstr(edata->desc, "INLET") != NULL)
    949 		return TRUE;
    950 	if (strstr(edata->desc, "DIODE") != NULL)
    951 		return TRUE;
    952 	if (strstr(edata->desc, "TUNNEL") != NULL)
    953 		return TRUE;
    954 	return false;
    955 }
    956 
    957 int
    958 smu_get_datablock(int id, uint8_t *buf, size_t len)
    959 {
    960 	struct smu_cmd cmd;
    961 
    962 	cmd.cmd = SMU_PARTITION;
    963 	cmd.len = 2;
    964 	cmd.data[0] = SMU_PARTITION_LATEST;
    965 	cmd.data[1] = id;
    966 	smu_do_cmd(smu0, &cmd, 100);
    967 
    968 	cmd.data[4] = cmd.data[0];
    969 	cmd.data[5] = cmd.data[1];
    970 
    971 	cmd.cmd = SMU_MISC;
    972 	cmd.len = 7;
    973 	cmd.data[0] = SMU_MISC_GET_DATA;
    974 	cmd.data[1] = 4;
    975 	cmd.data[2] = 0;
    976 	cmd.data[3] = 0;
    977 	cmd.data[6] = len;
    978 	smu_do_cmd(smu0, &cmd, 100);
    979 
    980 	memcpy(buf, cmd.data, len);
    981 	return 0;
    982 }
    983