xref: /openbsd-src/sys/arch/macppc/dev/smu.c (revision 91f110e064cd7c194e59e019b83bb7496c1c84d4)
1 /*	$OpenBSD: smu.c,v 1.23 2011/05/15 09:10:26 mpi 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/pci/macobio.h>
36 
37 int     smu_match(struct device *, void *, void *);
38 void    smu_attach(struct device *, struct device *, void *);
39 
40 #define SMU_MAXFANS	3
41 
42 struct smu_fan {
43 	u_int8_t	reg;
44 	u_int16_t	min_rpm;
45 	u_int16_t	max_rpm;
46 	u_int16_t	unmanaged_rpm;
47 	struct ksensor	sensor;
48 };
49 
50 #define SMU_MAXSENSORS	4
51 
52 struct smu_sensor {
53 	u_int8_t	reg;
54 	struct ksensor	sensor;
55 };
56 
57 struct smu_softc {
58         struct device   sc_dev;
59 
60 	/* SMU command buffer. */
61         bus_dma_tag_t   sc_dmat;
62         bus_dmamap_t    sc_cmdmap;
63         bus_dma_segment_t sc_cmdseg[1];
64         caddr_t         sc_cmd;
65 	struct rwlock	sc_lock;
66 
67 	/* Doorbell and mailbox. */
68 	struct ppc_bus_space sc_mem_bus_space;
69 	bus_space_tag_t sc_memt;
70 	bus_space_handle_t sc_gpioh;
71 	bus_space_handle_t sc_buffh;
72 
73 	struct smu_fan	sc_fans[SMU_MAXFANS];
74 	int		sc_num_fans;
75 
76 	struct smu_sensor sc_sensors[SMU_MAXSENSORS];
77 	int		sc_num_sensors;
78 
79 	struct ksensordev sc_sensordev;
80 
81 	u_int16_t	sc_cpu_diode_scale;
82 	int16_t		sc_cpu_diode_offset;
83 	u_int16_t	sc_cpu_volt_scale;
84 	int16_t		sc_cpu_volt_offset;
85 	u_int16_t	sc_cpu_curr_scale;
86 	int16_t		sc_cpu_curr_offset;
87 
88 	u_int16_t	sc_slots_pow_scale;
89 	int16_t		sc_slots_pow_offset;
90 
91 	struct i2c_controller sc_i2c_tag;
92 };
93 
94 struct cfattach smu_ca = {
95         sizeof(struct smu_softc), smu_match, smu_attach
96 };
97 
98 struct cfdriver smu_cd = {
99         NULL, "smu", DV_DULL,
100 };
101 
102 /* SMU command */
103 struct smu_cmd {
104         u_int8_t        cmd;
105         u_int8_t        len;
106         u_int8_t        data[254];
107 };
108 #define SMU_CMDSZ       sizeof(struct smu_cmd)
109 
110 /* RTC */
111 #define SMU_RTC			0x8e
112 #define SMU_RTC_SET_DATETIME	0x80
113 #define SMU_RTC_GET_DATETIME	0x81
114 
115 /* ADC */
116 #define SMU_ADC			0xd8
117 
118 /* Fan control */
119 #define SMU_FAN			0x4a
120 
121 /* Data partitions */
122 #define SMU_PARTITION		0x3e
123 #define SMU_PARTITION_LATEST	0x01
124 #define SMU_PARTITION_BASE	0x02
125 #define SMU_PARTITION_UPDATE	0x03
126 
127 /* I2C */
128 #define SMU_I2C			0x9a
129 #define SMU_I2C_SIMPLE		0x00
130 #define SMU_I2C_NORMAL		0x01
131 #define SMU_I2C_COMBINED	0x02
132 
133 /* Power Management */
134 #define SMU_POWER		0xaa
135 
136 /* Miscellaneous */
137 #define SMU_MISC		0xee
138 #define SMU_MISC_GET_DATA	0x02
139 
140 int	smu_intr(void *);
141 
142 int	smu_do_cmd(struct smu_softc *, int);
143 int	smu_time_read(time_t *);
144 int	smu_time_write(time_t);
145 int	smu_get_datablock(struct smu_softc *sc, u_int8_t, u_int8_t *, size_t);
146 int	smu_fan_set_rpm(struct smu_softc *, struct smu_fan *, u_int16_t);
147 int	smu_fan_refresh(struct smu_softc *, struct smu_fan *);
148 int	smu_sensor_refresh(struct smu_softc *, struct smu_sensor *);
149 void	smu_refresh_sensors(void *);
150 
151 int	smu_i2c_acquire_bus(void *, int);
152 void	smu_i2c_release_bus(void *, int);
153 int	smu_i2c_exec(void *, i2c_op_t, i2c_addr_t,
154 	    const void *, size_t, void *buf, size_t, int);
155 
156 void	smu_slew_voltage(u_int);
157 
158 int
159 smu_match(struct device *parent, void *cf, void *aux)
160 {
161         struct confargs *ca = aux;
162 
163         if (strcmp(ca->ca_name, "smu") == 0)
164                 return (1);
165         return (0);
166 }
167 
168 /* XXX */
169 extern struct powerpc_bus_dma_tag pci_bus_dma_tag;
170 
171 void
172 smu_attach(struct device *parent, struct device *self, void *aux)
173 {
174         struct smu_softc *sc = (struct smu_softc *)self;
175 	struct confargs *ca = aux;
176 	struct i2cbus_attach_args iba;
177 	struct smu_fan *fan;
178 	struct smu_sensor *sensor;
179 	int nseg, node;
180 	char type[32], loc[32];
181 	u_int32_t reg, intr, gpio, val;
182 	u_int8_t data[12];
183 
184 	/* XXX */
185 	sc->sc_mem_bus_space.bus_base = 0x80000000;
186 	sc->sc_mem_bus_space.bus_size = 0;
187 	sc->sc_mem_bus_space.bus_io = 0;
188 	sc->sc_memt = &sc->sc_mem_bus_space;
189 
190 	/* Map smu-doorbell gpio. */
191 	if (OF_getprop(ca->ca_node, "platform-doorbell-ack",
192 	        &node, sizeof node) <= 0 ||
193 	    OF_getprop(node, "reg", &reg, sizeof reg) <= 0 ||
194 	    OF_getprop(node, "interrupts", &intr, sizeof intr) <= 0 ||
195 	    OF_getprop(OF_parent(node), "reg", &gpio, sizeof gpio) <= 0) {
196 		printf(": cannot find smu-doorbell gpio\n");
197 		return;
198 	}
199 	if (bus_space_map(sc->sc_memt, gpio + reg, 1, 0, &sc->sc_gpioh)) {
200 		printf(": cannot map smu-doorbell gpio\n");
201 		return;
202 	}
203 
204 	/* XXX Should get this from OF. */
205 	if (bus_space_map(sc->sc_memt, 0x860c, 4, 0, &sc->sc_buffh)) {
206 		printf(": cannot map smu-doorbell buffer\n");
207 		return;
208 	}
209 
210 	/* XXX */
211         sc->sc_dmat = &pci_bus_dma_tag;
212 
213 	/* Allocate and map SMU command buffer.  */
214 	if (bus_dmamem_alloc(sc->sc_dmat, SMU_CMDSZ, 0, 0,
215             sc->sc_cmdseg, 1, &nseg, BUS_DMA_NOWAIT)) {
216                 printf(": cannot allocate cmd buffer\n");
217                 return;
218         }
219         if (bus_dmamem_map(sc->sc_dmat, sc->sc_cmdseg, nseg,
220             SMU_CMDSZ, &sc->sc_cmd, BUS_DMA_NOWAIT)) {
221                 printf(": cannot map cmd buffer\n");
222                 bus_dmamem_free(sc->sc_dmat, sc->sc_cmdseg, 1);
223                 return;
224         }
225         if (bus_dmamap_create(sc->sc_dmat, SMU_CMDSZ, 1, SMU_CMDSZ, 0,
226             BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &sc->sc_cmdmap)) {
227                 printf(": cannot create cmd dmamap\n");
228                 bus_dmamem_unmap(sc->sc_dmat, sc->sc_cmd, SMU_CMDSZ);
229                 bus_dmamem_free(sc->sc_dmat, sc->sc_cmdseg, 1);
230                 return;
231         }
232         if (bus_dmamap_load(sc->sc_dmat, sc->sc_cmdmap, sc->sc_cmd,
233             SMU_CMDSZ, NULL, BUS_DMA_NOWAIT)) {
234                 printf(": cannot load cmd dmamap\n");
235                 bus_dmamap_destroy(sc->sc_dmat, sc->sc_cmdmap);
236                 bus_dmamem_unmap(sc->sc_dmat, sc->sc_cmd, SMU_CMDSZ);
237                 bus_dmamem_free(sc->sc_dmat, sc->sc_cmdseg, nseg);
238                 return;
239         }
240 
241 	rw_init(&sc->sc_lock, sc->sc_dev.dv_xname);
242 
243 	/* Establish smu-doorbell interrupt. */
244 	mac_intr_establish(parent, intr, IST_EDGE, IPL_BIO,
245 	    smu_intr, sc, sc->sc_dev.dv_xname);
246 
247 	/* Initialize global variables that control RTC functionality. */
248 	time_read = smu_time_read;
249 	time_write = smu_time_write;
250 
251 	/* Fans */
252 	node = OF_getnodebyname(ca->ca_node, "rpm-fans");
253 	if (node == 0)
254 		node = OF_getnodebyname(ca->ca_node, "fans");
255 	for (node = OF_child(node); node; node = OF_peer(node)) {
256 		if (OF_getprop(node, "reg", &reg, sizeof reg) <= 0 ||
257 		    OF_getprop(node, "device_type", type, sizeof type) <= 0)
258 			continue;
259 
260 		if (strcmp(type, "fan-rpm-control") != 0) {
261 			printf(": unsupported fan type: %s\n", type);
262 			return;
263 		}
264 
265 		if (sc->sc_num_fans >= SMU_MAXFANS) {
266 			printf(": too many fans\n");
267 			return;
268 		}
269 
270 		fan = &sc->sc_fans[sc->sc_num_fans++];
271 		fan->sensor.type = SENSOR_FANRPM;
272 		fan->sensor.flags = SENSOR_FINVALID;
273 		fan->reg = reg;
274 
275 		if (OF_getprop(node, "min-value", &val, sizeof val) <= 0)
276 			val = 0;
277 		fan->min_rpm = val;
278 		if (OF_getprop(node, "max-value", &val, sizeof val) <= 0)
279 			val = 0xffff;
280 		fan->max_rpm = val;
281 		if (OF_getprop(node, "unmanage-value", &val, sizeof val) <= 0)
282 			val = fan->max_rpm;
283 		fan->unmanaged_rpm = val;
284 
285 		if (OF_getprop(node, "location", loc, sizeof loc) <= 0)
286 			strlcpy(loc, "Unknown", sizeof loc);
287 		strlcpy(fan->sensor.desc, loc, sizeof sensor->sensor.desc);
288 
289 		/* Start running fans at their "unmanaged" speed. */
290 		smu_fan_set_rpm(sc, fan, fan->unmanaged_rpm);
291 
292 		sensor_attach(&sc->sc_sensordev, &fan->sensor);
293 	}
294 
295 	/*
296 	 * Bail out if we didn't find any fans.  If we don't set the
297 	 * fans to a safe speed, but tickle the SMU periodically by
298 	 * reading sensors, the fans will never spin up and the
299 	 * machine might overheat.
300 	 */
301 	if (sc->sc_num_fans == 0) {
302 		printf(": no fans\n");
303 		return;
304 	}
305 
306 	/* Sensors */
307 	node = OF_getnodebyname(ca->ca_node, "sensors");
308 	for (node = OF_child(node); node; node = OF_peer(node)) {
309 		if (OF_getprop(node, "reg", &val, sizeof val) <= 0 ||
310 		    OF_getprop(node, "device_type", type, sizeof type) <= 0)
311 			continue;
312 
313 		if (sc->sc_num_sensors >= SMU_MAXSENSORS) {
314 			printf(": too many sensors\n");
315 			return;
316 		}
317 
318 		sensor = &sc->sc_sensors[sc->sc_num_sensors++];
319 		sensor->sensor.flags = SENSOR_FINVALID;
320 		sensor->reg = val;
321 
322 		if (strcmp(type, "current-sensor") == 0) {
323 			sensor->sensor.type = SENSOR_AMPS;
324 		} else if (strcmp(type, "temp-sensor") == 0) {
325 			sensor->sensor.type = SENSOR_TEMP;
326 		} else if (strcmp(type, "voltage-sensor") == 0) {
327 			sensor->sensor.type = SENSOR_VOLTS_DC;
328 		} else if (strcmp(type, "power-sensor") == 0) {
329 			sensor->sensor.type = SENSOR_WATTS;
330 		} else {
331 			sensor->sensor.type = SENSOR_INTEGER;
332 		}
333 
334 		if (OF_getprop(node, "location", loc, sizeof loc) <= 0)
335 			strlcpy(loc, "Unknown", sizeof loc);
336 		strlcpy(sensor->sensor.desc, loc, sizeof sensor->sensor.desc);
337 
338 		sensor_attach(&sc->sc_sensordev, &sensor->sensor);
339 	}
340 
341 	/* Register sensor device with sysctl */
342 	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
343 	    sizeof(sc->sc_sensordev.xname));
344 	sensordev_install(&sc->sc_sensordev);
345 
346 	/* CPU temperature diode calibration */
347 	smu_get_datablock(sc, 0x18, data, sizeof data);
348 	sc->sc_cpu_diode_scale = (data[4] << 8) + data[5];
349 	sc->sc_cpu_diode_offset = (data[6] << 8) + data[7];
350 
351 	/* CPU power (voltage and current) calibration */
352 	smu_get_datablock(sc, 0x21, data, sizeof data);
353 	sc->sc_cpu_volt_scale = (data[4] << 8) + data[5];
354 	sc->sc_cpu_volt_offset = (data[6] << 8) + data[7];
355 	sc->sc_cpu_curr_scale = (data[8] << 8) + data[9];
356 	sc->sc_cpu_curr_offset = (data[10] << 8) + data[11];
357 
358 	/* Slots power calibration */
359 	smu_get_datablock(sc, 0x78, data, sizeof data);
360 	sc->sc_slots_pow_scale = (data[4] << 8) + data[5];
361 	sc->sc_slots_pow_offset = (data[6] << 8) + data[7];
362 
363 	sensor_task_register(sc, smu_refresh_sensors, 5);
364 	printf("\n");
365 
366 	ppc64_slew_voltage = smu_slew_voltage;
367 
368 	sc->sc_i2c_tag.ic_cookie = sc;
369 	sc->sc_i2c_tag.ic_acquire_bus = smu_i2c_acquire_bus;
370 	sc->sc_i2c_tag.ic_release_bus = smu_i2c_release_bus;
371 	sc->sc_i2c_tag.ic_exec = smu_i2c_exec;
372 
373 	/*
374 	 * Early versions of the SMU have the i2c bus node directly
375 	 * below the "smu" node, while later models have an
376 	 * intermediate "smu-i2c-control" node.
377 	 */
378 	node = OF_getnodebyname(ca->ca_node, "smu-i2c-control");
379 	if (node)
380 		node = OF_child(node);
381 	else
382 		node = OF_getnodebyname(ca->ca_node, "i2c");
383 
384 	bzero(&iba, sizeof iba);
385 	iba.iba_name = "iic";
386 	iba.iba_tag = &sc->sc_i2c_tag;
387 	iba.iba_bus_scan = maciic_scan;
388 	iba.iba_bus_scan_arg = &node;
389 	config_found(&sc->sc_dev, &iba, NULL);
390 }
391 
392 int
393 smu_intr(void *arg)
394 {
395 	wakeup(arg);
396 	return 1;
397 }
398 
399 int
400 smu_do_cmd(struct smu_softc *sc, int timo)
401 {
402 	struct smu_cmd *cmd = (struct smu_cmd *)sc->sc_cmd;
403 	u_int8_t gpio, ack = ~cmd->cmd;
404 	int error;
405 
406 	/* Write to mailbox.  */
407 	bus_space_write_4(sc->sc_memt, sc->sc_buffh, 0,
408 	    sc->sc_cmdmap->dm_segs->ds_addr);
409 
410 	/* Flush to RAM. */
411 	asm __volatile__ ("dcbst 0,%0; sync" :: "r"(sc->sc_cmd): "memory");
412 
413 	/* Ring doorbell.  */
414 	bus_space_write_1(sc->sc_memt, sc->sc_gpioh, 0, GPIO_DDR_OUTPUT);
415 
416 	do {
417 		error = tsleep(sc, PWAIT, "smu", (timo * hz) / 1000);
418 		if (error)
419 			return (error);
420 		gpio = bus_space_read_1(sc->sc_memt, sc->sc_gpioh, 0);
421 	} while (!(gpio & (GPIO_DATA)));
422 
423 	/* CPU might have brought back the cache line. */
424 	asm __volatile__ ("dcbf 0,%0; sync" :: "r"(sc->sc_cmd) : "memory");
425 
426 	if (cmd->cmd != ack)
427 		return (EIO);
428 	return (0);
429 }
430 
431 int
432 smu_time_read(time_t *secs)
433 {
434 	struct smu_softc *sc = smu_cd.cd_devs[0];
435 	struct smu_cmd *cmd = (struct smu_cmd *)sc->sc_cmd;
436 	struct clock_ymdhms dt;
437 	int error;
438 
439 	rw_enter_write(&sc->sc_lock);
440 
441 	cmd->cmd = SMU_RTC;
442 	cmd->len = 1;
443 	cmd->data[0] = SMU_RTC_GET_DATETIME;
444 	error = smu_do_cmd(sc, 800);
445 	if (error) {
446 		rw_exit_write(&sc->sc_lock);
447 
448 		*secs = 0;
449 		return (error);
450 	}
451 
452 	dt.dt_year = 2000 + FROMBCD(cmd->data[6]);
453 	dt.dt_mon = FROMBCD(cmd->data[5]);
454 	dt.dt_day = FROMBCD(cmd->data[4]);
455 	dt.dt_hour = FROMBCD(cmd->data[2]);
456 	dt.dt_min = FROMBCD(cmd->data[1]);
457 	dt.dt_sec = FROMBCD(cmd->data[0]);
458 
459 	rw_exit_write(&sc->sc_lock);
460 
461 	*secs = clock_ymdhms_to_secs(&dt);
462 	return (0);
463 }
464 
465 int
466 smu_time_write(time_t secs)
467 {
468 	struct smu_softc *sc = smu_cd.cd_devs[0];
469 	struct smu_cmd *cmd = (struct smu_cmd *)sc->sc_cmd;
470 	struct clock_ymdhms dt;
471 	int error;
472 
473 	clock_secs_to_ymdhms(secs, &dt);
474 
475 	rw_enter_write(&sc->sc_lock);
476 
477 	cmd->cmd = SMU_RTC;
478 	cmd->len = 8;
479 	cmd->data[0] = SMU_RTC_SET_DATETIME;
480 	cmd->data[1] = TOBCD(dt.dt_sec);
481 	cmd->data[2] = TOBCD(dt.dt_min);
482 	cmd->data[3] = TOBCD(dt.dt_hour);
483 	cmd->data[4] = TOBCD(dt.dt_wday);
484 	cmd->data[5] = TOBCD(dt.dt_day);
485 	cmd->data[6] = TOBCD(dt.dt_mon);
486 	cmd->data[7] = TOBCD(dt.dt_year - 2000);
487 	error = smu_do_cmd(sc, 800);
488 
489 	rw_exit_write(&sc->sc_lock);
490 
491 	return (error);
492 }
493 
494 
495 int
496 smu_get_datablock(struct smu_softc *sc, u_int8_t id, u_int8_t *buf, size_t len)
497 {
498 	struct smu_cmd *cmd = (struct smu_cmd *)sc->sc_cmd;
499 	u_int8_t addr[4];
500 	int error;
501 
502 	cmd->cmd = SMU_PARTITION;
503 	cmd->len = 2;
504 	cmd->data[0] = SMU_PARTITION_LATEST;
505 	cmd->data[1] = id;
506 	error = smu_do_cmd(sc, 800);
507 	if (error)
508 		return (error);
509 
510 	addr[0] = 0x00;
511 	addr[1] = 0x00;
512 	addr[2] = cmd->data[0];
513 	addr[3] = cmd->data[1];
514 
515 	cmd->cmd = SMU_MISC;
516 	cmd->len = 7;
517 	cmd->data[0] = SMU_MISC_GET_DATA;
518 	cmd->data[1] = sizeof(u_int32_t);
519 	cmd->data[2] = addr[0];
520 	cmd->data[3] = addr[1];
521 	cmd->data[4] = addr[2];
522 	cmd->data[5] = addr[3];
523 	cmd->data[6] = len;
524 	error = smu_do_cmd(sc, 800);
525 	if (error)
526 		return (error);
527 
528 	memcpy(buf, cmd->data, len);
529 	return (0);
530 }
531 
532 int
533 smu_fan_set_rpm(struct smu_softc *sc, struct smu_fan *fan, u_int16_t rpm)
534 {
535 	struct smu_cmd *cmd = (struct smu_cmd *)sc->sc_cmd;
536 
537 	/*
538 	 * On the PowerMac8,2 this command expects the requested fan
539 	 * speed at a different location in the command block than on
540 	 * the PowerMac8,1.  We simply store the value at both
541 	 * locations.
542 	 */
543 	cmd->cmd = SMU_FAN;
544 	cmd->len = 14;
545 	cmd->data[0] = 0x00;	/* fan-rpm-control */
546 	cmd->data[1] = 0x01 << fan->reg;
547 	cmd->data[2] = cmd->data[2 + fan->reg * 2] = (rpm >> 8) & 0xff;
548 	cmd->data[3] = cmd->data[3 + fan->reg * 2] = (rpm & 0xff);
549 	return smu_do_cmd(sc, 800);
550 }
551 
552 int
553 smu_fan_refresh(struct smu_softc *sc, struct smu_fan *fan)
554 {
555 	struct smu_cmd *cmd = (struct smu_cmd *)sc->sc_cmd;
556 	int error;
557 
558 	cmd->cmd = SMU_FAN;
559 	cmd->len = 2;
560 	cmd->data[0] = 0x01;	/* fan-rpm-control */
561 	cmd->data[1] = 0x01 << fan->reg;
562 	error = smu_do_cmd(sc, 800);
563 	if (error) {
564 		fan->sensor.flags = SENSOR_FINVALID;
565 		return (error);
566 	}
567 	fan->sensor.value = (cmd->data[1] << 8) + cmd->data[2];
568 	fan->sensor.flags = 0;
569 	return (0);
570 }
571 
572 int
573 smu_sensor_refresh(struct smu_softc *sc, struct smu_sensor *sensor)
574 {
575 	struct smu_cmd *cmd = (struct smu_cmd *)sc->sc_cmd;
576 	int64_t value;
577 	int error;
578 
579 	cmd->cmd = SMU_ADC;
580 	cmd->len = 1;
581 	cmd->data[0] = sensor->reg;
582 	error = smu_do_cmd(sc, 800);
583 	if (error) {
584 		sensor->sensor.flags = SENSOR_FINVALID;
585 		return (error);
586 	}
587 	value = (cmd->data[0] << 8) + cmd->data[1];
588 	switch (sensor->sensor.type) {
589 	case SENSOR_TEMP:
590 		value *= sc->sc_cpu_diode_scale;
591 		value >>= 3;
592 		value += ((int64_t)sc->sc_cpu_diode_offset) << 9;
593 		value <<= 1;
594 
595 		/* Convert from 16.16 fixed point degC into muK. */
596 		value *= 15625;
597 		value /= 1024;
598 		value += 273150000;
599 		break;
600 
601 	case SENSOR_VOLTS_DC:
602 		value *= sc->sc_cpu_volt_scale;
603 		value += sc->sc_cpu_volt_offset;
604 		value <<= 4;
605 
606 		/* Convert from 16.16 fixed point V into muV. */
607 		value *= 15625;
608 		value /= 1024;
609 		break;
610 
611 	case SENSOR_AMPS:
612 		value *= sc->sc_cpu_curr_scale;
613 		value += sc->sc_cpu_curr_offset;
614 		value <<= 4;
615 
616 		/* Convert from 16.16 fixed point A into muA. */
617 		value *= 15625;
618 		value /= 1024;
619 		break;
620 
621 	case SENSOR_WATTS:
622 		value *= sc->sc_slots_pow_scale;
623 		value += sc->sc_slots_pow_offset;
624 		value <<= 4;
625 
626 		/* Convert from 16.16 fixed point W into muW. */
627 		value *= 15625;
628 		value /= 1024;
629 		break;
630 
631 	default:
632 		break;
633 	}
634 	sensor->sensor.value = value;
635 	sensor->sensor.flags = 0;
636 	return (0);
637 }
638 
639 void
640 smu_refresh_sensors(void *arg)
641 {
642 	struct smu_softc *sc = arg;
643 	int i;
644 
645 	rw_enter_write(&sc->sc_lock);
646 	for (i = 0; i < sc->sc_num_sensors; i++)
647 		smu_sensor_refresh(sc, &sc->sc_sensors[i]);
648 	for (i = 0; i < sc->sc_num_fans; i++)
649 		smu_fan_refresh(sc, &sc->sc_fans[i]);
650 	rw_exit_write(&sc->sc_lock);
651 }
652 
653 int
654 smu_i2c_acquire_bus(void *cookie, int flags)
655 {
656 	struct smu_softc *sc = cookie;
657 
658 	if (flags & I2C_F_POLL)
659 		return (0);
660 
661 	return (rw_enter(&sc->sc_lock, RW_WRITE));
662 }
663 
664 void
665 smu_i2c_release_bus(void *cookie, int flags)
666 {
667 	struct smu_softc *sc = cookie;
668 
669         if (flags & I2C_F_POLL)
670                 return;
671 
672 	rw_exit(&sc->sc_lock);
673 }
674 
675 int
676 smu_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
677     const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
678 {
679 	struct smu_softc *sc = cookie;
680 	struct smu_cmd *cmd = (struct smu_cmd *)sc->sc_cmd;
681 	u_int8_t smu_op = SMU_I2C_NORMAL;
682 	int error, retries = 10;
683 
684 	if (!I2C_OP_STOP_P(op) || cmdlen > 3 || len > 5)
685 		return (EINVAL);
686 
687 	if(cmdlen == 0)
688 		smu_op = SMU_I2C_SIMPLE;
689 	else if (I2C_OP_READ_P(op))
690 		smu_op = SMU_I2C_COMBINED;
691 
692 	cmd->cmd = SMU_I2C;
693 	cmd->len = 9 + len;
694 	cmd->data[0] = 0xb;
695 	cmd->data[1] = smu_op;
696 	cmd->data[2] = addr << 1;
697 	cmd->data[3] = cmdlen;
698 	memcpy (&cmd->data[4], cmdbuf, cmdlen);
699 	cmd->data[7] = addr << 1 | I2C_OP_READ_P(op);
700 	cmd->data[8] = len;
701 	memcpy(&cmd->data[9], buf, len);
702 
703 	error = smu_do_cmd(sc, 250);
704 	if (error)
705 		return error;
706 
707 	while (retries--) {
708 		cmd->cmd = SMU_I2C;
709 		cmd->len = 1;
710 		cmd->data[0] = 0;
711 		memset(&cmd->data[1], 0xff, len);
712 
713 		error = smu_do_cmd(sc, 250);
714 		if (error)
715 			return error;
716 
717 		if ((cmd->data[0] & 0x80) == 0)
718 			break;
719 		if (cmd->data[0] == 0xfd)
720 			break;
721 
722 		DELAY(15 * 1000);
723 	}
724 
725 	if (cmd->data[0] & 0x80)
726 		return (EIO);
727 
728 	if (I2C_OP_READ_P(op))
729 		memcpy(buf, &cmd->data[1], len);
730 	return (0);
731 }
732 
733 void
734 smu_slew_voltage(u_int freq_scale)
735 {
736 	struct smu_softc *sc = smu_cd.cd_devs[0];
737 	struct smu_cmd *cmd = (struct smu_cmd *)sc->sc_cmd;
738 
739 	cmd->cmd = SMU_POWER;
740 	cmd->len = 8;
741 	memcpy(cmd->data, "VSLEW", 5);
742 	cmd->data[5] = 0xff;
743 	cmd->data[6] = 1;
744 	cmd->data[7] = freq_scale;
745 
746 	smu_do_cmd(sc, 250);
747 }
748