smu.c revision 208841
1/*-
2 * Copyright (c) 2009 Nathan Whitehorn
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 AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
19 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
21 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 */
27
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD: head/sys/powerpc/powermac/smu.c 208841 2010-06-05 17:50:20Z nwhitehorn $");
30
31#include <sys/param.h>
32#include <sys/bus.h>
33#include <sys/systm.h>
34#include <sys/module.h>
35#include <sys/conf.h>
36#include <sys/cpu.h>
37#include <sys/clock.h>
38#include <sys/ctype.h>
39#include <sys/kernel.h>
40#include <sys/kthread.h>
41#include <sys/reboot.h>
42#include <sys/rman.h>
43#include <sys/sysctl.h>
44#include <sys/unistd.h>
45
46#include <machine/bus.h>
47#include <machine/intr_machdep.h>
48#include <machine/md_var.h>
49
50#include <dev/iicbus/iicbus.h>
51#include <dev/iicbus/iiconf.h>
52#include <dev/led/led.h>
53#include <dev/ofw/openfirm.h>
54#include <dev/ofw/ofw_bus.h>
55#include <dev/ofw/ofw_bus_subr.h>
56#include <powerpc/powermac/macgpiovar.h>
57
58#include "clock_if.h"
59#include "iicbus_if.h"
60
61struct smu_cmd {
62	volatile uint8_t cmd;
63	uint8_t		len;
64	uint8_t		data[254];
65
66	STAILQ_ENTRY(smu_cmd) cmd_q;
67};
68
69STAILQ_HEAD(smu_cmdq, smu_cmd);
70
71struct smu_fan {
72	cell_t	reg;
73	cell_t	min_rpm;
74	cell_t	max_rpm;
75	cell_t	unmanaged_rpm;
76	char	location[32];
77
78	int	old_style;
79	int	setpoint;
80};
81
82struct smu_sensor {
83	cell_t	reg;
84	char	location[32];
85	enum {
86		SMU_CURRENT_SENSOR,
87		SMU_VOLTAGE_SENSOR,
88		SMU_POWER_SENSOR,
89		SMU_TEMP_SENSOR
90	} type;
91};
92
93struct smu_softc {
94	device_t	sc_dev;
95	struct mtx	sc_mtx;
96
97	struct resource	*sc_memr;
98	int		sc_memrid;
99
100	bus_dma_tag_t	sc_dmatag;
101	bus_space_tag_t	sc_bt;
102	bus_space_handle_t sc_mailbox;
103
104	struct smu_cmd	*sc_cmd, *sc_cur_cmd;
105	bus_addr_t	sc_cmd_phys;
106	bus_dmamap_t	sc_cmd_dmamap;
107	struct smu_cmdq	sc_cmdq;
108
109	struct smu_fan	*sc_fans;
110	int		sc_nfans;
111	struct smu_sensor *sc_sensors;
112	int		sc_nsensors;
113
114	int		sc_doorbellirqid;
115	struct resource	*sc_doorbellirq;
116	void		*sc_doorbellirqcookie;
117
118	struct proc	*sc_fanmgt_proc;
119	time_t		sc_lastuserchange;
120
121	/* Calibration data */
122	uint16_t	sc_cpu_diode_scale;
123	int16_t		sc_cpu_diode_offset;
124
125	uint16_t	sc_cpu_volt_scale;
126	int16_t		sc_cpu_volt_offset;
127	uint16_t	sc_cpu_curr_scale;
128	int16_t		sc_cpu_curr_offset;
129
130	uint16_t	sc_slots_pow_scale;
131	int16_t		sc_slots_pow_offset;
132
133	/* Thermal management parameters */
134	int		sc_target_temp;		/* Default 55 C */
135	int		sc_critical_temp;	/* Default 90 C */
136
137	struct cdev 	*sc_leddev;
138};
139
140/* regular bus attachment functions */
141
142static int	smu_probe(device_t);
143static int	smu_attach(device_t);
144static const struct ofw_bus_devinfo *
145    smu_get_devinfo(device_t bus, device_t dev);
146
147/* cpufreq notification hooks */
148
149static void	smu_cpufreq_pre_change(device_t, const struct cf_level *level);
150static void	smu_cpufreq_post_change(device_t, const struct cf_level *level);
151
152/* clock interface */
153static int	smu_gettime(device_t dev, struct timespec *ts);
154static int	smu_settime(device_t dev, struct timespec *ts);
155
156/* utility functions */
157static int	smu_run_cmd(device_t dev, struct smu_cmd *cmd, int wait);
158static int	smu_get_datablock(device_t dev, int8_t id, uint8_t *buf,
159		    size_t len);
160static void	smu_attach_i2c(device_t dev, phandle_t i2croot);
161static void	smu_attach_fans(device_t dev, phandle_t fanroot);
162static void	smu_attach_sensors(device_t dev, phandle_t sensroot);
163static void	smu_fan_management_proc(void *xdev);
164static void	smu_manage_fans(device_t smu);
165static void	smu_set_sleepled(void *xdev, int onoff);
166static int	smu_server_mode(SYSCTL_HANDLER_ARGS);
167static void	smu_doorbell_intr(void *xdev);
168
169/* where to find the doorbell GPIO */
170
171static device_t	smu_doorbell = NULL;
172
173static device_method_t  smu_methods[] = {
174	/* Device interface */
175	DEVMETHOD(device_probe,		smu_probe),
176	DEVMETHOD(device_attach,	smu_attach),
177
178	/* Clock interface */
179	DEVMETHOD(clock_gettime,	smu_gettime),
180	DEVMETHOD(clock_settime,	smu_settime),
181
182	/* ofw_bus interface */
183	DEVMETHOD(bus_child_pnpinfo_str,ofw_bus_gen_child_pnpinfo_str),
184	DEVMETHOD(ofw_bus_get_devinfo,	smu_get_devinfo),
185	DEVMETHOD(ofw_bus_get_compat,	ofw_bus_gen_get_compat),
186	DEVMETHOD(ofw_bus_get_model,	ofw_bus_gen_get_model),
187	DEVMETHOD(ofw_bus_get_name,	ofw_bus_gen_get_name),
188	DEVMETHOD(ofw_bus_get_node,	ofw_bus_gen_get_node),
189	DEVMETHOD(ofw_bus_get_type,	ofw_bus_gen_get_type),
190
191	{ 0, 0 },
192};
193
194static driver_t smu_driver = {
195	"smu",
196	smu_methods,
197	sizeof(struct smu_softc)
198};
199
200static devclass_t smu_devclass;
201
202DRIVER_MODULE(smu, nexus, smu_driver, smu_devclass, 0, 0);
203MALLOC_DEFINE(M_SMU, "smu", "SMU Sensor Information");
204
205#define SMU_MAILBOX		0x8000860c
206#define SMU_FANMGT_INTERVAL	1000 /* ms */
207
208/* Command types */
209#define SMU_ADC			0xd8
210#define SMU_FAN			0x4a
211#define SMU_I2C			0x9a
212#define  SMU_I2C_SIMPLE		0x00
213#define  SMU_I2C_NORMAL		0x01
214#define  SMU_I2C_COMBINED	0x02
215#define SMU_MISC		0xee
216#define  SMU_MISC_GET_DATA	0x02
217#define  SMU_MISC_LED_CTRL	0x04
218#define SMU_POWER		0xaa
219#define SMU_POWER_EVENTS	0x8f
220#define  SMU_PWR_GET_POWERUP	0x00
221#define  SMU_PWR_SET_POWERUP	0x01
222#define  SMU_PWR_CLR_POWERUP	0x02
223#define SMU_RTC			0x8e
224#define  SMU_RTC_GET		0x81
225#define  SMU_RTC_SET		0x80
226
227/* Power event types */
228#define SMU_WAKEUP_KEYPRESS	0x01
229#define SMU_WAKEUP_AC_INSERT	0x02
230#define SMU_WAKEUP_AC_CHANGE	0x04
231#define SMU_WAKEUP_RING		0x10
232
233/* Data blocks */
234#define SMU_CPUTEMP_CAL		0x18
235#define SMU_CPUVOLT_CAL		0x21
236#define SMU_SLOTPW_CAL		0x78
237
238/* Partitions */
239#define SMU_PARTITION		0x3e
240#define SMU_PARTITION_LATEST	0x01
241#define SMU_PARTITION_BASE	0x02
242#define SMU_PARTITION_UPDATE	0x03
243
244static int
245smu_probe(device_t dev)
246{
247	const char *name = ofw_bus_get_name(dev);
248
249	if (strcmp(name, "smu") != 0)
250		return (ENXIO);
251
252	device_set_desc(dev, "Apple System Management Unit");
253	return (0);
254}
255
256static void
257smu_phys_callback(void *xsc, bus_dma_segment_t *segs, int nsegs, int error)
258{
259	struct smu_softc *sc = xsc;
260
261	sc->sc_cmd_phys = segs[0].ds_addr;
262}
263
264static int
265smu_attach(device_t dev)
266{
267	struct smu_softc *sc;
268	phandle_t	node, child;
269	uint8_t		data[12];
270
271	sc = device_get_softc(dev);
272
273	mtx_init(&sc->sc_mtx, "smu", NULL, MTX_DEF);
274	sc->sc_cur_cmd = NULL;
275	sc->sc_doorbellirqid = -1;
276
277	/*
278	 * Map the mailbox area. This should be determined from firmware,
279	 * but I have not found a simple way to do that.
280	 */
281	bus_dma_tag_create(NULL, 16, 0, BUS_SPACE_MAXADDR_32BIT,
282	    BUS_SPACE_MAXADDR, NULL, NULL, PAGE_SIZE, 1, PAGE_SIZE, 0, NULL,
283	    NULL, &(sc->sc_dmatag));
284	sc->sc_bt = &bs_le_tag;
285	bus_space_map(sc->sc_bt, SMU_MAILBOX, 4, 0, &sc->sc_mailbox);
286
287	/*
288	 * Allocate the command buffer. This can be anywhere in the low 4 GB
289	 * of memory.
290	 */
291	bus_dmamem_alloc(sc->sc_dmatag, (void **)&sc->sc_cmd, BUS_DMA_WAITOK |
292	    BUS_DMA_ZERO, &sc->sc_cmd_dmamap);
293	bus_dmamap_load(sc->sc_dmatag, sc->sc_cmd_dmamap,
294	    sc->sc_cmd, PAGE_SIZE, smu_phys_callback, sc, 0);
295	STAILQ_INIT(&sc->sc_cmdq);
296
297	/*
298	 * Set up handlers to change CPU voltage when CPU frequency is changed.
299	 */
300	EVENTHANDLER_REGISTER(cpufreq_pre_change, smu_cpufreq_pre_change, dev,
301	    EVENTHANDLER_PRI_ANY);
302	EVENTHANDLER_REGISTER(cpufreq_post_change, smu_cpufreq_post_change, dev,
303	    EVENTHANDLER_PRI_ANY);
304
305	/*
306	 * Detect and attach child devices.
307	 */
308	node = ofw_bus_get_node(dev);
309	for (child = OF_child(node); child != 0; child = OF_peer(child)) {
310		char name[32];
311		memset(name, 0, sizeof(name));
312		OF_getprop(child, "name", name, sizeof(name));
313
314		if (strncmp(name, "rpm-fans", 9) == 0 ||
315		    strncmp(name, "fans", 5) == 0)
316			smu_attach_fans(dev, child);
317
318		if (strncmp(name, "sensors", 8) == 0)
319			smu_attach_sensors(dev, child);
320
321		if (strncmp(name, "smu-i2c-control", 15) == 0)
322			smu_attach_i2c(dev, child);
323	}
324
325	/* Some SMUs have the I2C children directly under the bus. */
326	smu_attach_i2c(dev, node);
327
328	/*
329	 * Collect calibration constants.
330	 */
331	smu_get_datablock(dev, SMU_CPUTEMP_CAL, data, sizeof(data));
332	sc->sc_cpu_diode_scale = (data[4] << 8) + data[5];
333	sc->sc_cpu_diode_offset = (data[6] << 8) + data[7];
334
335	smu_get_datablock(dev, SMU_CPUVOLT_CAL, data, sizeof(data));
336	sc->sc_cpu_volt_scale = (data[4] << 8) + data[5];
337	sc->sc_cpu_volt_offset = (data[6] << 8) + data[7];
338	sc->sc_cpu_curr_scale = (data[8] << 8) + data[9];
339	sc->sc_cpu_curr_offset = (data[10] << 8) + data[11];
340
341	smu_get_datablock(dev, SMU_SLOTPW_CAL, data, sizeof(data));
342	sc->sc_slots_pow_scale = (data[4] << 8) + data[5];
343	sc->sc_slots_pow_offset = (data[6] << 8) + data[7];
344
345	/*
346	 * Set up simple-minded thermal management.
347	 */
348	sc->sc_target_temp = 55;
349	sc->sc_critical_temp = 90;
350
351	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
352	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
353	    "target_temp", CTLTYPE_INT | CTLFLAG_RW, &sc->sc_target_temp,
354	    sizeof(int), "Target temperature (C)");
355	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
356	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
357	    "critical_temp", CTLTYPE_INT | CTLFLAG_RW,
358	    &sc->sc_critical_temp, sizeof(int), "Critical temperature (C)");
359
360	kproc_create(smu_fan_management_proc, dev, &sc->sc_fanmgt_proc,
361	    RFHIGHPID, 0, "smu_thermal");
362
363	/*
364	 * Set up LED interface
365	 */
366	sc->sc_leddev = led_create(smu_set_sleepled, dev, "sleepled");
367
368	/*
369	 * Reset on power loss behavior
370	 */
371
372	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
373            SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
374	    "server_mode", CTLTYPE_INT | CTLFLAG_RW, dev, 0,
375	    smu_server_mode, "I", "Enable reboot after power failure");
376
377	/*
378	 * Set up doorbell interrupt.
379	 */
380	sc->sc_doorbellirqid = 0;
381	sc->sc_doorbellirq = bus_alloc_resource_any(smu_doorbell, SYS_RES_IRQ,
382	    &sc->sc_doorbellirqid, RF_ACTIVE);
383	bus_setup_intr(smu_doorbell, sc->sc_doorbellirq,
384	    INTR_TYPE_MISC | INTR_MPSAFE, NULL, smu_doorbell_intr, dev,
385	    &sc->sc_doorbellirqcookie);
386	powerpc_config_intr(rman_get_start(sc->sc_doorbellirq),
387	    INTR_TRIGGER_EDGE, INTR_POLARITY_LOW);
388
389	/*
390	 * Connect RTC interface.
391	 */
392	clock_register(dev, 1000);
393
394	return (bus_generic_attach(dev));
395}
396
397static const struct ofw_bus_devinfo *
398smu_get_devinfo(device_t bus, device_t dev)
399{
400
401	return (device_get_ivars(dev));
402}
403
404static void
405smu_send_cmd(device_t dev, struct smu_cmd *cmd)
406{
407	struct smu_softc *sc;
408
409	sc = device_get_softc(dev);
410
411	mtx_assert(&sc->sc_mtx, MA_OWNED);
412
413	powerpc_pow_enabled = 0;	/* SMU cannot work if we go to NAP */
414	sc->sc_cur_cmd = cmd;
415
416	/* Copy the command to the mailbox */
417	sc->sc_cmd->cmd = cmd->cmd;
418	sc->sc_cmd->len = cmd->len;
419	memcpy(sc->sc_cmd->data, cmd->data, sizeof(cmd->data));
420	bus_dmamap_sync(sc->sc_dmatag, sc->sc_cmd_dmamap, BUS_DMASYNC_PREWRITE);
421	bus_space_write_4(sc->sc_bt, sc->sc_mailbox, 0, sc->sc_cmd_phys);
422
423	/* Flush the cacheline it is in -- SMU bypasses the cache */
424	__asm __volatile("sync; dcbf 0,%0; sync" :: "r"(sc->sc_cmd): "memory");
425
426	/* Ring SMU doorbell */
427	macgpio_write(smu_doorbell, GPIO_DDR_OUTPUT);
428}
429
430static void
431smu_doorbell_intr(void *xdev)
432{
433	device_t smu;
434	struct smu_softc *sc;
435	int doorbell_ack;
436
437	smu = xdev;
438	doorbell_ack = macgpio_read(smu_doorbell);
439	sc = device_get_softc(smu);
440
441	if (doorbell_ack != (GPIO_DDR_OUTPUT | GPIO_LEVEL_RO | GPIO_DATA))
442		return;
443
444	mtx_lock(&sc->sc_mtx);
445
446	if (sc->sc_cur_cmd == NULL)	/* spurious */
447		goto done;
448
449	/* Check result. First invalidate the cache again... */
450	__asm __volatile("dcbf 0,%0; sync" :: "r"(sc->sc_cmd) : "memory");
451
452	bus_dmamap_sync(sc->sc_dmatag, sc->sc_cmd_dmamap, BUS_DMASYNC_POSTREAD);
453
454	sc->sc_cur_cmd->cmd = sc->sc_cmd->cmd;
455	sc->sc_cur_cmd->len = sc->sc_cmd->len;
456	memcpy(sc->sc_cur_cmd->data, sc->sc_cmd->data,
457	    sizeof(sc->sc_cmd->data));
458	wakeup(sc->sc_cur_cmd);
459	sc->sc_cur_cmd = NULL;
460	powerpc_pow_enabled = 1;
461
462    done:
463	/* Queue next command if one is pending */
464	if (STAILQ_FIRST(&sc->sc_cmdq) != NULL) {
465		sc->sc_cur_cmd = STAILQ_FIRST(&sc->sc_cmdq);
466		STAILQ_REMOVE_HEAD(&sc->sc_cmdq, cmd_q);
467		smu_send_cmd(smu, sc->sc_cur_cmd);
468	}
469
470	mtx_unlock(&sc->sc_mtx);
471}
472
473static int
474smu_run_cmd(device_t dev, struct smu_cmd *cmd, int wait)
475{
476	struct smu_softc *sc;
477	uint8_t cmd_code;
478	int error;
479
480	sc = device_get_softc(dev);
481	cmd_code = cmd->cmd;
482
483	mtx_lock(&sc->sc_mtx);
484	if (sc->sc_cur_cmd != NULL) {
485		STAILQ_INSERT_TAIL(&sc->sc_cmdq, cmd, cmd_q);
486	} else
487		smu_send_cmd(dev, cmd);
488	mtx_unlock(&sc->sc_mtx);
489
490	if (!wait)
491		return (0);
492
493	if (sc->sc_doorbellirqid < 0) {
494		/* Poll if the IRQ has not been set up yet */
495		do {
496			DELAY(50);
497			smu_doorbell_intr(dev);
498		} while (sc->sc_cur_cmd != NULL);
499	} else {
500		/* smu_doorbell_intr will wake us when the command is ACK'ed */
501		error = tsleep(cmd, 0, "smu", 800 * hz / 1000);
502		if (error != 0)
503			smu_doorbell_intr(dev);	/* One last chance */
504
505		if (error != 0) {
506		    mtx_lock(&sc->sc_mtx);
507		    if (cmd->cmd == cmd_code) {	/* Never processed */
508			/* Abort this command if we timed out */
509			if (sc->sc_cur_cmd == cmd)
510				sc->sc_cur_cmd = NULL;
511			else
512				STAILQ_REMOVE(&sc->sc_cmdq, cmd, smu_cmd,
513				    cmd_q);
514			mtx_unlock(&sc->sc_mtx);
515			return (error);
516		    }
517		    error = 0;
518		    mtx_unlock(&sc->sc_mtx);
519		}
520	}
521
522	/* SMU acks the command by inverting the command bits */
523	if (cmd->cmd == ((~cmd_code) & 0xff))
524		error = 0;
525	else
526		error = EIO;
527
528	return (error);
529}
530
531static int
532smu_get_datablock(device_t dev, int8_t id, uint8_t *buf, size_t len)
533{
534	struct smu_cmd cmd;
535	uint8_t addr[4];
536
537	cmd.cmd = SMU_PARTITION;
538	cmd.len = 2;
539	cmd.data[0] = SMU_PARTITION_LATEST;
540	cmd.data[1] = id;
541
542	smu_run_cmd(dev, &cmd, 1);
543
544	addr[0] = addr[1] = 0;
545	addr[2] = cmd.data[0];
546	addr[3] = cmd.data[1];
547
548	cmd.cmd = SMU_MISC;
549	cmd.len = 7;
550	cmd.data[0] = SMU_MISC_GET_DATA;
551	cmd.data[1] = sizeof(addr);
552	memcpy(&cmd.data[2], addr, sizeof(addr));
553	cmd.data[6] = len;
554
555	smu_run_cmd(dev, &cmd, 1);
556	memcpy(buf, cmd.data, len);
557	return (0);
558}
559
560static void
561smu_slew_cpu_voltage(device_t dev, int to)
562{
563	struct smu_cmd cmd;
564
565	cmd.cmd = SMU_POWER;
566	cmd.len = 8;
567	cmd.data[0] = 'V';
568	cmd.data[1] = 'S';
569	cmd.data[2] = 'L';
570	cmd.data[3] = 'E';
571	cmd.data[4] = 'W';
572	cmd.data[5] = 0xff;
573	cmd.data[6] = 1;
574	cmd.data[7] = to;
575
576	smu_run_cmd(dev, &cmd, 1);
577}
578
579static void
580smu_cpufreq_pre_change(device_t dev, const struct cf_level *level)
581{
582	/*
583	 * Make sure the CPU voltage is raised before we raise
584	 * the clock.
585	 */
586
587	if (level->rel_set[0].freq == 10000 /* max */)
588		smu_slew_cpu_voltage(dev, 0);
589}
590
591static void
592smu_cpufreq_post_change(device_t dev, const struct cf_level *level)
593{
594	/* We are safe to reduce CPU voltage after a downward transition */
595
596	if (level->rel_set[0].freq < 10000 /* max */)
597		smu_slew_cpu_voltage(dev, 1); /* XXX: 1/4 voltage for 970MP? */
598}
599
600/* Routines for probing the SMU doorbell GPIO */
601static int doorbell_probe(device_t dev);
602static int doorbell_attach(device_t dev);
603
604static device_method_t  doorbell_methods[] = {
605	/* Device interface */
606	DEVMETHOD(device_probe,		doorbell_probe),
607	DEVMETHOD(device_attach,	doorbell_attach),
608	{ 0, 0 },
609};
610
611static driver_t doorbell_driver = {
612	"smudoorbell",
613	doorbell_methods,
614	0
615};
616
617static devclass_t doorbell_devclass;
618
619DRIVER_MODULE(smudoorbell, macgpio, doorbell_driver, doorbell_devclass, 0, 0);
620
621static int
622doorbell_probe(device_t dev)
623{
624	const char *name = ofw_bus_get_name(dev);
625
626	if (strcmp(name, "smu-doorbell") != 0)
627		return (ENXIO);
628
629	device_set_desc(dev, "SMU Doorbell GPIO");
630	device_quiet(dev);
631	return (0);
632}
633
634static int
635doorbell_attach(device_t dev)
636{
637	smu_doorbell = dev;
638	return (0);
639}
640
641/*
642 * Sensor and fan management
643 */
644
645static int
646smu_fan_set_rpm(device_t smu, struct smu_fan *fan, int rpm)
647{
648	struct smu_cmd cmd;
649	int error;
650
651	cmd.cmd = SMU_FAN;
652	error = EIO;
653
654	/* Clamp to allowed range */
655	rpm = max(fan->min_rpm, rpm);
656	rpm = min(fan->max_rpm, rpm);
657
658	/*
659	 * Apple has two fan control mechanisms. We can't distinguish
660	 * them except by seeing if the new one fails. If the new one
661	 * fails, use the old one.
662	 */
663
664	if (!fan->old_style) {
665		cmd.len = 4;
666		cmd.data[0] = 0x30;
667		cmd.data[1] = fan->reg;
668		cmd.data[2] = (rpm >> 8) & 0xff;
669		cmd.data[3] = rpm & 0xff;
670
671		error = smu_run_cmd(smu, &cmd, 1);
672		if (error)
673			fan->old_style = 1;
674	}
675
676	if (fan->old_style) {
677		cmd.len = 14;
678		cmd.data[0] = 0;
679		cmd.data[1] = 1 << fan->reg;
680		cmd.data[2 + 2*fan->reg] = (rpm >> 8) & 0xff;
681		cmd.data[3 + 2*fan->reg] = rpm & 0xff;
682		error = smu_run_cmd(smu, &cmd, 1);
683	}
684
685	if (error == 0)
686		fan->setpoint = rpm;
687
688	return (error);
689}
690
691static int
692smu_fan_read_rpm(device_t smu, struct smu_fan *fan)
693{
694	struct smu_cmd cmd;
695	int rpm, error;
696
697	if (!fan->old_style) {
698		cmd.cmd = SMU_FAN;
699		cmd.len = 2;
700		cmd.data[0] = 0x31;
701		cmd.data[1] = fan->reg;
702
703		error = smu_run_cmd(smu, &cmd, 1);
704		if (error)
705			fan->old_style = 1;
706
707		rpm = (cmd.data[0] << 8) | cmd.data[1];
708	}
709
710	if (fan->old_style) {
711		cmd.cmd = SMU_FAN;
712		cmd.len = 1;
713		cmd.data[0] = 1;
714
715		error = smu_run_cmd(smu, &cmd, 1);
716		if (error)
717			return (error);
718
719		rpm = (cmd.data[fan->reg*2+1] << 8) | cmd.data[fan->reg*2+2];
720	}
721
722	return (rpm);
723}
724
725static int
726smu_fanrpm_sysctl(SYSCTL_HANDLER_ARGS)
727{
728	device_t smu;
729	struct smu_softc *sc;
730	struct smu_fan *fan;
731	int rpm, error;
732
733	smu = arg1;
734	sc = device_get_softc(smu);
735	fan = &sc->sc_fans[arg2];
736
737	rpm = smu_fan_read_rpm(smu, fan);
738	if (rpm < 0)
739		return (rpm);
740
741	error = sysctl_handle_int(oidp, &rpm, 0, req);
742
743	if (error || !req->newptr)
744		return (error);
745
746	sc->sc_lastuserchange = time_uptime;
747
748	return (smu_fan_set_rpm(smu, fan, rpm));
749}
750
751static void
752smu_attach_fans(device_t dev, phandle_t fanroot)
753{
754	struct smu_fan *fan;
755	struct smu_softc *sc;
756	struct sysctl_oid *oid, *fanroot_oid;
757	struct sysctl_ctx_list *ctx;
758	phandle_t child;
759	char type[32], sysctl_name[32];
760	int i;
761
762	sc = device_get_softc(dev);
763	sc->sc_nfans = 0;
764
765	for (child = OF_child(fanroot); child != 0; child = OF_peer(child))
766		sc->sc_nfans++;
767
768	if (sc->sc_nfans == 0) {
769		device_printf(dev, "WARNING: No fans detected!\n");
770		return;
771	}
772
773	sc->sc_fans = malloc(sc->sc_nfans * sizeof(struct smu_fan), M_SMU,
774	    M_WAITOK | M_ZERO);
775
776	fan = sc->sc_fans;
777	sc->sc_nfans = 0;
778
779	ctx = device_get_sysctl_ctx(dev);
780	fanroot_oid = SYSCTL_ADD_NODE(ctx,
781	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "fans",
782	    CTLFLAG_RD, 0, "SMU Fan Information");
783
784	for (child = OF_child(fanroot); child != 0; child = OF_peer(child)) {
785		OF_getprop(child, "device_type", type, sizeof(type));
786		if (strcmp(type, "fan-rpm-control") != 0)
787			continue;
788
789		fan->old_style = 0;
790		OF_getprop(child, "reg", &fan->reg, sizeof(cell_t));
791		OF_getprop(child, "min-value", &fan->min_rpm, sizeof(cell_t));
792		OF_getprop(child, "max-value", &fan->max_rpm, sizeof(cell_t));
793
794		if (OF_getprop(child, "unmanaged-value", &fan->unmanaged_rpm,
795		    sizeof(cell_t)) != sizeof(cell_t))
796			fan->unmanaged_rpm = fan->max_rpm;
797
798		fan->setpoint = smu_fan_read_rpm(dev, fan);
799
800		OF_getprop(child, "location", fan->location,
801		    sizeof(fan->location));
802
803		/* Add sysctls */
804		for (i = 0; i < strlen(fan->location); i++) {
805			sysctl_name[i] = tolower(fan->location[i]);
806			if (isspace(sysctl_name[i]))
807				sysctl_name[i] = '_';
808		}
809		sysctl_name[i] = 0;
810
811		oid = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(fanroot_oid),
812		    OID_AUTO, sysctl_name, CTLFLAG_RD, 0, "Fan Information");
813		SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "minrpm",
814		    CTLTYPE_INT | CTLFLAG_RD, &fan->min_rpm, sizeof(cell_t),
815		    "Minimum allowed RPM");
816		SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "maxrpm",
817		    CTLTYPE_INT | CTLFLAG_RD, &fan->max_rpm, sizeof(cell_t),
818		    "Maximum allowed RPM");
819		SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "rpm",
820		    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev,
821		    sc->sc_nfans, smu_fanrpm_sysctl, "I", "Fan RPM");
822
823		fan++;
824		sc->sc_nfans++;
825	}
826}
827
828static int
829smu_sensor_read(device_t smu, struct smu_sensor *sens, int *val)
830{
831	struct smu_cmd cmd;
832	struct smu_softc *sc;
833	int64_t value;
834	int error;
835
836	cmd.cmd = SMU_ADC;
837	cmd.len = 1;
838	cmd.data[0] = sens->reg;
839	error = 0;
840
841	error = smu_run_cmd(smu, &cmd, 1);
842	if (error != 0)
843		return (error);
844
845	sc = device_get_softc(smu);
846	value = (cmd.data[0] << 8) | cmd.data[1];
847
848	switch (sens->type) {
849	case SMU_TEMP_SENSOR:
850		value *= sc->sc_cpu_diode_scale;
851		value >>= 3;
852		value += ((int64_t)sc->sc_cpu_diode_offset) << 9;
853		value <<= 1;
854
855		/* Convert from 16.16 fixed point degC into integer C. */
856		value >>= 16;
857		break;
858	case SMU_VOLTAGE_SENSOR:
859		value *= sc->sc_cpu_volt_scale;
860		value += sc->sc_cpu_volt_offset;
861		value <<= 4;
862
863		/* Convert from 16.16 fixed point V into mV. */
864		value *= 15625;
865		value /= 1024;
866		value /= 1000;
867		break;
868	case SMU_CURRENT_SENSOR:
869		value *= sc->sc_cpu_curr_scale;
870		value += sc->sc_cpu_curr_offset;
871		value <<= 4;
872
873		/* Convert from 16.16 fixed point A into mA. */
874		value *= 15625;
875		value /= 1024;
876		value /= 1000;
877		break;
878	case SMU_POWER_SENSOR:
879		value *= sc->sc_slots_pow_scale;
880		value += sc->sc_slots_pow_offset;
881		value <<= 4;
882
883		/* Convert from 16.16 fixed point W into mW. */
884		value *= 15625;
885		value /= 1024;
886		value /= 1000;
887		break;
888	}
889
890	*val = value;
891	return (0);
892}
893
894static int
895smu_sensor_sysctl(SYSCTL_HANDLER_ARGS)
896{
897	device_t smu;
898	struct smu_softc *sc;
899	struct smu_sensor *sens;
900	int value, error;
901
902	smu = arg1;
903	sc = device_get_softc(smu);
904	sens = &sc->sc_sensors[arg2];
905
906	error = smu_sensor_read(smu, sens, &value);
907	if (error != 0)
908		return (error);
909
910	error = sysctl_handle_int(oidp, &value, 0, req);
911
912	return (error);
913}
914
915static void
916smu_attach_sensors(device_t dev, phandle_t sensroot)
917{
918	struct smu_sensor *sens;
919	struct smu_softc *sc;
920	struct sysctl_oid *sensroot_oid;
921	struct sysctl_ctx_list *ctx;
922	phandle_t child;
923	char type[32];
924	int i;
925
926	sc = device_get_softc(dev);
927	sc->sc_nsensors = 0;
928
929	for (child = OF_child(sensroot); child != 0; child = OF_peer(child))
930		sc->sc_nsensors++;
931
932	if (sc->sc_nsensors == 0) {
933		device_printf(dev, "WARNING: No sensors detected!\n");
934		return;
935	}
936
937	sc->sc_sensors = malloc(sc->sc_nsensors * sizeof(struct smu_sensor),
938	    M_SMU, M_WAITOK | M_ZERO);
939
940	sens = sc->sc_sensors;
941	sc->sc_nsensors = 0;
942
943	ctx = device_get_sysctl_ctx(dev);
944	sensroot_oid = SYSCTL_ADD_NODE(ctx,
945	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "sensors",
946	    CTLFLAG_RD, 0, "SMU Sensor Information");
947
948	for (child = OF_child(sensroot); child != 0; child = OF_peer(child)) {
949		char sysctl_name[40], sysctl_desc[40];
950		const char *units;
951
952		OF_getprop(child, "device_type", type, sizeof(type));
953
954		if (strcmp(type, "current-sensor") == 0) {
955			sens->type = SMU_CURRENT_SENSOR;
956			units = "mA";
957		} else if (strcmp(type, "temp-sensor") == 0) {
958			sens->type = SMU_TEMP_SENSOR;
959			units = "C";
960		} else if (strcmp(type, "voltage-sensor") == 0) {
961			sens->type = SMU_VOLTAGE_SENSOR;
962			units = "mV";
963		} else if (strcmp(type, "power-sensor") == 0) {
964			sens->type = SMU_POWER_SENSOR;
965			units = "mW";
966		} else {
967			continue;
968		}
969
970		OF_getprop(child, "reg", &sens->reg, sizeof(cell_t));
971		OF_getprop(child, "location", sens->location,
972		    sizeof(sens->location));
973
974		for (i = 0; i < strlen(sens->location); i++) {
975			sysctl_name[i] = tolower(sens->location[i]);
976			if (isspace(sysctl_name[i]))
977				sysctl_name[i] = '_';
978		}
979		sysctl_name[i] = 0;
980
981		sprintf(sysctl_desc,"%s (%s)", sens->location, units);
982
983		SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(sensroot_oid), OID_AUTO,
984		    sysctl_name, CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
985		    dev, sc->sc_nsensors, smu_sensor_sysctl, "I", sysctl_desc);
986
987		sens++;
988		sc->sc_nsensors++;
989	}
990}
991
992static void
993smu_fan_management_proc(void *xdev)
994{
995	device_t smu = xdev;
996
997	while(1) {
998		smu_manage_fans(smu);
999		pause("smu", SMU_FANMGT_INTERVAL * hz / 1000);
1000	}
1001}
1002
1003static void
1004smu_manage_fans(device_t smu)
1005{
1006	struct smu_softc *sc;
1007	int i, maxtemp, temp, factor, error;
1008
1009	sc = device_get_softc(smu);
1010
1011	maxtemp = 0;
1012	for (i = 0; i < sc->sc_nsensors; i++) {
1013		if (sc->sc_sensors[i].type != SMU_TEMP_SENSOR)
1014			continue;
1015
1016		error = smu_sensor_read(smu, &sc->sc_sensors[i], &temp);
1017		if (error == 0 && temp > maxtemp)
1018			maxtemp = temp;
1019	}
1020
1021	if (maxtemp > sc->sc_critical_temp) {
1022		device_printf(smu, "WARNING: Current system temperature (%d C) "
1023		    "exceeds critical temperature (%d C)! Shutting down!\n",
1024		    maxtemp, sc->sc_critical_temp);
1025		shutdown_nice(RB_POWEROFF);
1026	}
1027
1028	if (maxtemp - sc->sc_target_temp > 20)
1029		device_printf(smu, "WARNING: Current system temperature (%d C) "
1030		    "more than 20 degrees over target temperature (%d C)!\n",
1031		    maxtemp, sc->sc_target_temp);
1032
1033	if (time_uptime - sc->sc_lastuserchange < 3) {
1034		/*
1035		 * If we have heard from a user process in the last 3 seconds,
1036		 * go away.
1037		 */
1038
1039		return;
1040	}
1041
1042	if (maxtemp < 10) { /* Bail if no good sensors */
1043		for (i = 0; i < sc->sc_nfans; i++)
1044			smu_fan_set_rpm(smu, &sc->sc_fans[i],
1045			    sc->sc_fans[i].unmanaged_rpm);
1046		return;
1047	}
1048
1049	if (maxtemp - sc->sc_target_temp > 4)
1050		factor = 110;
1051	else if (maxtemp - sc->sc_target_temp > 1)
1052		factor = 105;
1053	else if (sc->sc_target_temp - maxtemp > 4)
1054		factor = 90;
1055	else if (sc->sc_target_temp - maxtemp > 1)
1056		factor = 95;
1057	else
1058		factor = 100;
1059
1060	for (i = 0; i < sc->sc_nfans; i++)
1061		smu_fan_set_rpm(smu, &sc->sc_fans[i],
1062		    (sc->sc_fans[i].setpoint * factor) / 100);
1063}
1064
1065static void
1066smu_set_sleepled(void *xdev, int onoff)
1067{
1068	static struct smu_cmd cmd;
1069	device_t smu = xdev;
1070
1071	cmd.cmd = SMU_MISC;
1072	cmd.len = 3;
1073	cmd.data[0] = SMU_MISC_LED_CTRL;
1074	cmd.data[1] = 0;
1075	cmd.data[2] = onoff;
1076
1077	smu_run_cmd(smu, &cmd, 0);
1078}
1079
1080static int
1081smu_server_mode(SYSCTL_HANDLER_ARGS)
1082{
1083	struct smu_cmd cmd;
1084	u_int server_mode;
1085	device_t smu = arg1;
1086	int error;
1087
1088	cmd.cmd = SMU_POWER_EVENTS;
1089	cmd.len = 1;
1090	cmd.data[0] = SMU_PWR_GET_POWERUP;
1091
1092	error = smu_run_cmd(smu, &cmd, 1);
1093
1094	if (error)
1095		return (error);
1096
1097	server_mode = (cmd.data[1] & SMU_WAKEUP_AC_INSERT) ? 1 : 0;
1098
1099	error = sysctl_handle_int(oidp, &server_mode, 0, req);
1100
1101	if (error || !req->newptr)
1102		return (error);
1103
1104	if (server_mode == 1)
1105		cmd.data[0] = SMU_PWR_SET_POWERUP;
1106	else if (server_mode == 0)
1107		cmd.data[0] = SMU_PWR_CLR_POWERUP;
1108	else
1109		return (EINVAL);
1110
1111	cmd.len = 3;
1112	cmd.data[1] = 0;
1113	cmd.data[2] = SMU_WAKEUP_AC_INSERT;
1114
1115	return (smu_run_cmd(smu, &cmd, 1));
1116}
1117
1118static int
1119smu_gettime(device_t dev, struct timespec *ts)
1120{
1121	struct smu_cmd cmd;
1122	struct clocktime ct;
1123
1124	cmd.cmd = SMU_RTC;
1125	cmd.len = 1;
1126	cmd.data[0] = SMU_RTC_GET;
1127
1128	if (smu_run_cmd(dev, &cmd, 1) != 0)
1129		return (ENXIO);
1130
1131	ct.nsec	= 0;
1132	ct.sec	= bcd2bin(cmd.data[0]);
1133	ct.min	= bcd2bin(cmd.data[1]);
1134	ct.hour	= bcd2bin(cmd.data[2]);
1135	ct.dow	= bcd2bin(cmd.data[3]);
1136	ct.day	= bcd2bin(cmd.data[4]);
1137	ct.mon	= bcd2bin(cmd.data[5]);
1138	ct.year	= bcd2bin(cmd.data[6]) + 2000;
1139
1140	return (clock_ct_to_ts(&ct, ts));
1141}
1142
1143static int
1144smu_settime(device_t dev, struct timespec *ts)
1145{
1146	struct smu_cmd cmd;
1147	struct clocktime ct;
1148
1149	cmd.cmd = SMU_RTC;
1150	cmd.len = 8;
1151	cmd.data[0] = SMU_RTC_SET;
1152
1153	clock_ts_to_ct(ts, &ct);
1154
1155	cmd.data[1] = bin2bcd(ct.sec);
1156	cmd.data[2] = bin2bcd(ct.min);
1157	cmd.data[3] = bin2bcd(ct.hour);
1158	cmd.data[4] = bin2bcd(ct.dow);
1159	cmd.data[5] = bin2bcd(ct.day);
1160	cmd.data[6] = bin2bcd(ct.mon);
1161	cmd.data[7] = bin2bcd(ct.year - 2000);
1162
1163	return (smu_run_cmd(dev, &cmd, 1));
1164}
1165
1166/* SMU I2C Interface */
1167
1168static int smuiic_probe(device_t dev);
1169static int smuiic_attach(device_t dev);
1170static int smuiic_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs);
1171static phandle_t smuiic_get_node(device_t bus, device_t dev);
1172
1173static device_method_t smuiic_methods[] = {
1174	/* device interface */
1175	DEVMETHOD(device_probe,         smuiic_probe),
1176	DEVMETHOD(device_attach,        smuiic_attach),
1177
1178	/* iicbus interface */
1179	DEVMETHOD(iicbus_callback,      iicbus_null_callback),
1180	DEVMETHOD(iicbus_transfer,      smuiic_transfer),
1181
1182	/* ofw_bus interface */
1183	DEVMETHOD(ofw_bus_get_node,     smuiic_get_node),
1184
1185	{ 0, 0 }
1186};
1187
1188struct smuiic_softc {
1189	struct mtx	sc_mtx;
1190	volatile int	sc_iic_inuse;
1191	int		sc_busno;
1192};
1193
1194static driver_t smuiic_driver = {
1195	"iichb",
1196	smuiic_methods,
1197	sizeof(struct smuiic_softc)
1198};
1199static devclass_t smuiic_devclass;
1200
1201DRIVER_MODULE(smuiic, smu, smuiic_driver, smuiic_devclass, 0, 0);
1202
1203static void
1204smu_attach_i2c(device_t smu, phandle_t i2croot)
1205{
1206	phandle_t child;
1207	device_t cdev;
1208	struct ofw_bus_devinfo *dinfo;
1209	char name[32];
1210
1211	for (child = OF_child(i2croot); child != 0; child = OF_peer(child)) {
1212		if (OF_getprop(child, "name", name, sizeof(name)) <= 0)
1213			continue;
1214
1215		if (strcmp(name, "i2c-bus") != 0 && strcmp(name, "i2c") != 0)
1216			continue;
1217
1218		dinfo = malloc(sizeof(struct ofw_bus_devinfo), M_SMU,
1219		    M_WAITOK | M_ZERO);
1220		if (ofw_bus_gen_setup_devinfo(dinfo, child) != 0) {
1221			free(dinfo, M_SMU);
1222			continue;
1223		}
1224
1225		cdev = device_add_child(smu, NULL, -1);
1226		if (cdev == NULL) {
1227			device_printf(smu, "<%s>: device_add_child failed\n",
1228			    dinfo->obd_name);
1229			ofw_bus_gen_destroy_devinfo(dinfo);
1230			free(dinfo, M_SMU);
1231			continue;
1232		}
1233		device_set_ivars(cdev, dinfo);
1234	}
1235}
1236
1237static int
1238smuiic_probe(device_t dev)
1239{
1240	const char *name;
1241
1242	name = ofw_bus_get_name(dev);
1243	if (name == NULL)
1244		return (ENXIO);
1245
1246	if (strcmp(name, "i2c-bus") == 0 || strcmp(name, "i2c") == 0) {
1247		device_set_desc(dev, "SMU I2C controller");
1248		return (0);
1249	}
1250
1251	return (ENXIO);
1252}
1253
1254static int
1255smuiic_attach(device_t dev)
1256{
1257	struct smuiic_softc *sc = device_get_softc(dev);
1258	mtx_init(&sc->sc_mtx, "smuiic", NULL, MTX_DEF);
1259	sc->sc_iic_inuse = 0;
1260
1261	/* Get our bus number */
1262	OF_getprop(ofw_bus_get_node(dev), "reg", &sc->sc_busno,
1263	    sizeof(sc->sc_busno));
1264
1265	/* Add the IIC bus layer */
1266	device_add_child(dev, "iicbus", -1);
1267
1268	return (bus_generic_attach(dev));
1269}
1270
1271static int
1272smuiic_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs)
1273{
1274	struct smuiic_softc *sc = device_get_softc(dev);
1275	struct smu_cmd cmd;
1276	int i, j, error;
1277
1278	mtx_lock(&sc->sc_mtx);
1279	while (sc->sc_iic_inuse)
1280		mtx_sleep(sc, &sc->sc_mtx, 0, "smuiic", 100);
1281
1282	sc->sc_iic_inuse = 1;
1283	error = 0;
1284
1285	for (i = 0; i < nmsgs; i++) {
1286		cmd.cmd = SMU_I2C;
1287		cmd.data[0] = sc->sc_busno;
1288		if (msgs[i].flags & IIC_M_NOSTOP)
1289			cmd.data[1] = SMU_I2C_COMBINED;
1290		else
1291			cmd.data[1] = SMU_I2C_SIMPLE;
1292
1293		cmd.data[2] = msgs[i].slave;
1294		if (msgs[i].flags & IIC_M_RD)
1295			cmd.data[2] |= 1;
1296
1297		if (msgs[i].flags & IIC_M_NOSTOP) {
1298			KASSERT(msgs[i].len < 4,
1299			    ("oversize I2C combined message"));
1300
1301			cmd.data[3] = min(msgs[i].len, 3);
1302			memcpy(&cmd.data[4], msgs[i].buf, min(msgs[i].len, 3));
1303			i++; /* Advance to next part of message */
1304		} else {
1305			cmd.data[3] = 0;
1306			memset(&cmd.data[4], 0, 3);
1307		}
1308
1309		cmd.data[7] = msgs[i].slave;
1310		if (msgs[i].flags & IIC_M_RD)
1311			cmd.data[7] |= 1;
1312
1313		cmd.data[8] = msgs[i].len;
1314		if (msgs[i].flags & IIC_M_RD) {
1315			memset(&cmd.data[9], 0xff, msgs[i].len);
1316			cmd.len = 9;
1317		} else {
1318			memcpy(&cmd.data[9], msgs[i].buf, msgs[i].len);
1319			cmd.len = 9 + msgs[i].len;
1320		}
1321
1322		mtx_unlock(&sc->sc_mtx);
1323		smu_run_cmd(device_get_parent(dev), &cmd, 1);
1324		mtx_lock(&sc->sc_mtx);
1325
1326		for (j = 0; j < 10; j++) {
1327			cmd.cmd = SMU_I2C;
1328			cmd.len = 1;
1329			cmd.data[0] = 0;
1330			memset(&cmd.data[1], 0xff, msgs[i].len);
1331
1332			mtx_unlock(&sc->sc_mtx);
1333			smu_run_cmd(device_get_parent(dev), &cmd, 1);
1334			mtx_lock(&sc->sc_mtx);
1335
1336			if (!(cmd.data[0] & 0x80))
1337				break;
1338
1339			mtx_sleep(sc, &sc->sc_mtx, 0, "smuiic", 10);
1340		}
1341
1342		if (cmd.data[0] & 0x80) {
1343			error = EIO;
1344			msgs[i].len = 0;
1345			goto exit;
1346		}
1347		memcpy(msgs[i].buf, &cmd.data[1], msgs[i].len);
1348		msgs[i].len = cmd.len - 1;
1349	}
1350
1351    exit:
1352	sc->sc_iic_inuse = 0;
1353	mtx_unlock(&sc->sc_mtx);
1354	wakeup(sc);
1355	return (error);
1356}
1357
1358static phandle_t
1359smuiic_get_node(device_t bus, device_t dev)
1360{
1361
1362	return (ofw_bus_get_node(bus));
1363}
1364
1365