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