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