pmu.c revision 262675
1/*-
2 * Copyright (c) 2006 Michael Lorenz
3 * Copyright 2008 by Nathan Whitehorn
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: stable/10/sys/powerpc/powermac/pmu.c 262675 2014-03-02 02:35:46Z jhibbits $");
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/module.h>
35#include <sys/bus.h>
36#include <sys/conf.h>
37#include <sys/kernel.h>
38#include <sys/clock.h>
39#include <sys/proc.h>
40#include <sys/reboot.h>
41#include <sys/sysctl.h>
42
43#include <dev/ofw/ofw_bus.h>
44#include <dev/ofw/openfirm.h>
45#include <dev/led/led.h>
46
47#include <machine/_inttypes.h>
48#include <machine/bus.h>
49#include <machine/cpu.h>
50#include <machine/hid.h>
51#include <machine/intr_machdep.h>
52#include <machine/md_var.h>
53#include <machine/pcb.h>
54#include <machine/pio.h>
55#include <machine/resource.h>
56
57#include <vm/vm.h>
58#include <vm/pmap.h>
59
60#include <sys/rman.h>
61
62#include <dev/adb/adb.h>
63
64#include "clock_if.h"
65#include "pmuvar.h"
66#include "viareg.h"
67#include "uninorthvar.h"	/* For unin_chip_sleep()/unin_chip_wake() */
68
69#define PMU_DEFAULTS	PMU_INT_TICK | PMU_INT_ADB | \
70	PMU_INT_PCEJECT | PMU_INT_SNDBRT | \
71	PMU_INT_BATTERY | PMU_INT_ENVIRONMENT
72
73/*
74 * Bus interface
75 */
76static int	pmu_probe(device_t);
77static int	pmu_attach(device_t);
78static int	pmu_detach(device_t);
79
80/*
81 * Clock interface
82 */
83static int	pmu_gettime(device_t dev, struct timespec *ts);
84static int	pmu_settime(device_t dev, struct timespec *ts);
85
86/*
87 * ADB Interface
88 */
89
90static u_int	pmu_adb_send(device_t dev, u_char command_byte, int len,
91		    u_char *data, u_char poll);
92static u_int	pmu_adb_autopoll(device_t dev, uint16_t mask);
93static u_int	pmu_poll(device_t dev);
94
95/*
96 * Power interface
97 */
98
99static void	pmu_shutdown(void *xsc, int howto);
100static void	pmu_set_sleepled(void *xsc, int onoff);
101static int	pmu_server_mode(SYSCTL_HANDLER_ARGS);
102static int	pmu_acline_state(SYSCTL_HANDLER_ARGS);
103static int	pmu_query_battery(struct pmu_softc *sc, int batt,
104		    struct pmu_battstate *info);
105static int	pmu_battquery_sysctl(SYSCTL_HANDLER_ARGS);
106
107/*
108 * List of battery-related sysctls we might ask for
109 */
110
111enum {
112	PMU_BATSYSCTL_PRESENT	= 1 << 8,
113	PMU_BATSYSCTL_CHARGING	= 2 << 8,
114	PMU_BATSYSCTL_CHARGE	= 3 << 8,
115	PMU_BATSYSCTL_MAXCHARGE = 4 << 8,
116	PMU_BATSYSCTL_CURRENT	= 5 << 8,
117	PMU_BATSYSCTL_VOLTAGE	= 6 << 8,
118	PMU_BATSYSCTL_TIME	= 7 << 8,
119	PMU_BATSYSCTL_LIFE	= 8 << 8
120};
121
122static device_method_t  pmu_methods[] = {
123	/* Device interface */
124	DEVMETHOD(device_probe,		pmu_probe),
125	DEVMETHOD(device_attach,	pmu_attach),
126        DEVMETHOD(device_detach,        pmu_detach),
127        DEVMETHOD(device_shutdown,      bus_generic_shutdown),
128
129	/* ADB bus interface */
130	DEVMETHOD(adb_hb_send_raw_packet,   pmu_adb_send),
131	DEVMETHOD(adb_hb_controller_poll,   pmu_poll),
132	DEVMETHOD(adb_hb_set_autopoll_mask, pmu_adb_autopoll),
133
134	/* Clock interface */
135	DEVMETHOD(clock_gettime,	pmu_gettime),
136	DEVMETHOD(clock_settime,	pmu_settime),
137
138	DEVMETHOD_END
139};
140
141static driver_t pmu_driver = {
142	"pmu",
143	pmu_methods,
144	sizeof(struct pmu_softc),
145};
146
147static devclass_t pmu_devclass;
148
149DRIVER_MODULE(pmu, macio, pmu_driver, pmu_devclass, 0, 0);
150DRIVER_MODULE(adb, pmu, adb_driver, adb_devclass, 0, 0);
151
152static int	pmuextint_probe(device_t);
153static int	pmuextint_attach(device_t);
154
155static device_method_t  pmuextint_methods[] = {
156	/* Device interface */
157	DEVMETHOD(device_probe,		pmuextint_probe),
158	DEVMETHOD(device_attach,	pmuextint_attach),
159
160	{0,0}
161};
162
163static driver_t pmuextint_driver = {
164	"pmuextint",
165	pmuextint_methods,
166	0
167};
168
169static devclass_t pmuextint_devclass;
170
171DRIVER_MODULE(pmuextint, macgpio, pmuextint_driver, pmuextint_devclass, 0, 0);
172
173/* Make sure uhid is loaded, as it turns off some of the ADB emulation */
174MODULE_DEPEND(pmu, usb, 1, 1, 1);
175
176static void pmu_intr(void *arg);
177static void pmu_in(struct pmu_softc *sc);
178static void pmu_out(struct pmu_softc *sc);
179static void pmu_ack_on(struct pmu_softc *sc);
180static void pmu_ack_off(struct pmu_softc *sc);
181static int pmu_send(void *cookie, int cmd, int length, uint8_t *in_msg,
182	int rlen, uint8_t *out_msg);
183static uint8_t pmu_read_reg(struct pmu_softc *sc, u_int offset);
184static void pmu_write_reg(struct pmu_softc *sc, u_int offset, uint8_t value);
185static int pmu_intr_state(struct pmu_softc *);
186
187/* these values shows that number of data returned after 'send' cmd is sent */
188static signed char pm_send_cmd_type[] = {
189	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
190	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
191	0x01, 0x01,   -1,   -1,   -1,   -1,   -1,   -1,
192	0x00, 0x00,   -1,   -1,   -1,   -1,   -1, 0x00,
193	  -1, 0x00, 0x02, 0x01, 0x01,   -1,   -1,   -1,
194	0x00,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
195	0x04, 0x14,   -1, 0x03,   -1,   -1,   -1,   -1,
196	0x00, 0x00, 0x02, 0x02,   -1,   -1,   -1,   -1,
197	0x01, 0x01,   -1,   -1,   -1,   -1,   -1,   -1,
198	0x00, 0x00,   -1,   -1, 0x01,   -1,   -1,   -1,
199	0x01, 0x00, 0x02, 0x02,   -1, 0x01, 0x03, 0x01,
200	0x00, 0x01, 0x00, 0x00, 0x00,   -1,   -1,   -1,
201	0x02,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
202	0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   -1,   -1,
203	0x01, 0x01, 0x01,   -1,   -1,   -1,   -1,   -1,
204	0x00, 0x00,   -1,   -1,   -1, 0x05, 0x04, 0x04,
205	0x04,   -1, 0x00,   -1,   -1,   -1,   -1,   -1,
206	0x00,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
207	0x01, 0x02,   -1,   -1,   -1,   -1,   -1,   -1,
208	0x00, 0x00,   -1,   -1,   -1,   -1,   -1,   -1,
209	0x02, 0x02, 0x02, 0x04,   -1, 0x00,   -1,   -1,
210	0x01, 0x01, 0x03, 0x02,   -1,   -1,   -1,   -1,
211	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
212	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
213	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
214	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
215	0x00,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
216	0x01, 0x01,   -1,   -1, 0x00, 0x00,   -1,   -1,
217	  -1, 0x04, 0x00,   -1,   -1,   -1,   -1,   -1,
218	0x03,   -1, 0x00,   -1, 0x00,   -1,   -1, 0x00,
219	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
220	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1
221};
222
223/* these values shows that number of data returned after 'receive' cmd is sent */
224static signed char pm_receive_cmd_type[] = {
225	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
226	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
227	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
228	0x02, 0x02,   -1,   -1,   -1,   -1,   -1, 0x00,
229	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
230	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
231	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
232	0x05, 0x15,   -1, 0x02,   -1,   -1,   -1,   -1,
233	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
234	0x02, 0x02,   -1,   -1,   -1,   -1,   -1,   -1,
235	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
236	0x02, 0x00, 0x03, 0x03,   -1,   -1,   -1,   -1,
237	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
238	0x04, 0x04, 0x03, 0x09,   -1,   -1,   -1,   -1,
239	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
240	  -1,   -1,   -1,   -1,   -1, 0x01, 0x01, 0x01,
241	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
242	0x06,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
243	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
244	0x02, 0x02,   -1,   -1,   -1,   -1,   -1,   -1,
245	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
246	0x02, 0x00, 0x00, 0x00,   -1,   -1,   -1,   -1,
247	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
248	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
249	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
250	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
251	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
252	0x02, 0x02,   -1,   -1, 0x02,   -1,   -1,   -1,
253	0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
254	  -1,   -1, 0x02,   -1,   -1,   -1,   -1, 0x00,
255	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
256	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
257};
258
259/* We only have one of each device, so globals are safe */
260static device_t pmu = NULL;
261static device_t pmu_extint = NULL;
262
263static int
264pmuextint_probe(device_t dev)
265{
266	const char *type = ofw_bus_get_type(dev);
267
268	if (strcmp(type, "extint-gpio1") != 0)
269                return (ENXIO);
270
271	device_set_desc(dev, "Apple PMU99 External Interrupt");
272	return (0);
273}
274
275static int
276pmu_probe(device_t dev)
277{
278	const char *type = ofw_bus_get_type(dev);
279
280	if (strcmp(type, "via-pmu") != 0)
281                return (ENXIO);
282
283	device_set_desc(dev, "Apple PMU99 Controller");
284	return (0);
285}
286
287
288static int
289setup_pmu_intr(device_t dev, device_t extint)
290{
291	struct pmu_softc *sc;
292	sc = device_get_softc(dev);
293
294	sc->sc_irqrid = 0;
295	sc->sc_irq = bus_alloc_resource_any(extint, SYS_RES_IRQ, &sc->sc_irqrid,
296           	RF_ACTIVE);
297        if (sc->sc_irq == NULL) {
298                device_printf(dev, "could not allocate interrupt\n");
299                return (ENXIO);
300        }
301
302	if (bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC | INTR_MPSAFE
303	    | INTR_ENTROPY, NULL, pmu_intr, dev, &sc->sc_ih) != 0) {
304                device_printf(dev, "could not setup interrupt\n");
305                bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqrid,
306                    sc->sc_irq);
307                return (ENXIO);
308        }
309
310	return (0);
311}
312
313static int
314pmuextint_attach(device_t dev)
315{
316	pmu_extint = dev;
317	if (pmu)
318		return (setup_pmu_intr(pmu,dev));
319
320	return (0);
321}
322
323static int
324pmu_attach(device_t dev)
325{
326	struct pmu_softc *sc;
327
328	int i;
329	uint8_t reg;
330	uint8_t cmd[2] = {2, 0};
331	uint8_t resp[16];
332	phandle_t node,child;
333	struct sysctl_ctx_list *ctx;
334	struct sysctl_oid *tree;
335
336	sc = device_get_softc(dev);
337	sc->sc_dev = dev;
338
339	sc->sc_memrid = 0;
340	sc->sc_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
341		          &sc->sc_memrid, RF_ACTIVE);
342
343	mtx_init(&sc->sc_mutex,"pmu",NULL,MTX_DEF | MTX_RECURSE);
344
345	if (sc->sc_memr == NULL) {
346		device_printf(dev, "Could not alloc mem resource!\n");
347		return (ENXIO);
348	}
349
350	/*
351	 * Our interrupt is attached to a GPIO pin. Depending on probe order,
352	 * we may not have found it yet. If we haven't, it will find us, and
353	 * attach our interrupt then.
354	 */
355	pmu = dev;
356	if (pmu_extint != NULL) {
357		if (setup_pmu_intr(dev,pmu_extint) != 0)
358			return (ENXIO);
359	}
360
361	sc->sc_autopoll = 0;
362	sc->sc_batteries = 0;
363	sc->adb_bus = NULL;
364	sc->sc_leddev = NULL;
365
366	/* Init PMU */
367
368	pmu_write_reg(sc, vBufB, pmu_read_reg(sc, vBufB) | vPB4);
369	pmu_write_reg(sc, vDirB, (pmu_read_reg(sc, vDirB) | vPB4) & ~vPB3);
370
371	reg = PMU_DEFAULTS;
372	pmu_send(sc, PMU_SET_IMASK, 1, &reg, 16, resp);
373
374	pmu_write_reg(sc, vIER, 0x94); /* make sure VIA interrupts are on */
375
376	pmu_send(sc, PMU_SYSTEM_READY, 1, cmd, 16, resp);
377	pmu_send(sc, PMU_GET_VERSION, 0, cmd, 16, resp);
378
379	/* Initialize child buses (ADB) */
380	node = ofw_bus_get_node(dev);
381
382	for (child = OF_child(node); child != 0; child = OF_peer(child)) {
383		char name[32];
384
385		memset(name, 0, sizeof(name));
386		OF_getprop(child, "name", name, sizeof(name));
387
388		if (bootverbose)
389			device_printf(dev, "PMU child <%s>\n",name);
390
391		if (strncmp(name, "adb", 4) == 0) {
392			sc->adb_bus = device_add_child(dev,"adb",-1);
393		}
394
395		if (strncmp(name, "power-mgt", 9) == 0) {
396			uint32_t prim_info[9];
397
398			if (OF_getprop(child, "prim-info", prim_info,
399			    sizeof(prim_info)) >= 7)
400				sc->sc_batteries = (prim_info[6] >> 16) & 0xff;
401
402			if (bootverbose && sc->sc_batteries > 0)
403				device_printf(dev, "%d batteries detected\n",
404				    sc->sc_batteries);
405		}
406	}
407
408	/*
409	 * Set up sysctls
410	 */
411
412	ctx = device_get_sysctl_ctx(dev);
413	tree = device_get_sysctl_tree(dev);
414
415	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
416	    "server_mode", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
417	    pmu_server_mode, "I", "Enable reboot after power failure");
418
419	if (sc->sc_batteries > 0) {
420		struct sysctl_oid *oid, *battroot;
421		char battnum[2];
422
423		SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
424		    "acline", CTLTYPE_INT | CTLFLAG_RD, sc, 0,
425		    pmu_acline_state, "I", "AC Line Status");
426
427		battroot = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
428		    "batteries", CTLFLAG_RD, 0, "Battery Information");
429
430		for (i = 0; i < sc->sc_batteries; i++) {
431			battnum[0] = i + '0';
432			battnum[1] = '\0';
433
434			oid = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(battroot),
435			    OID_AUTO, battnum, CTLFLAG_RD, 0,
436			    "Battery Information");
437
438			SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
439			    "present", CTLTYPE_INT | CTLFLAG_RD, sc,
440			    PMU_BATSYSCTL_PRESENT | i, pmu_battquery_sysctl,
441			    "I", "Battery present");
442			SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
443			    "charging", CTLTYPE_INT | CTLFLAG_RD, sc,
444			    PMU_BATSYSCTL_CHARGING | i, pmu_battquery_sysctl,
445			    "I", "Battery charging");
446			SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
447			    "charge", CTLTYPE_INT | CTLFLAG_RD, sc,
448			    PMU_BATSYSCTL_CHARGE | i, pmu_battquery_sysctl,
449			    "I", "Battery charge (mAh)");
450			SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
451			    "maxcharge", CTLTYPE_INT | CTLFLAG_RD, sc,
452			    PMU_BATSYSCTL_MAXCHARGE | i, pmu_battquery_sysctl,
453			    "I", "Maximum battery capacity (mAh)");
454			SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
455			    "rate", CTLTYPE_INT | CTLFLAG_RD, sc,
456			    PMU_BATSYSCTL_CURRENT | i, pmu_battquery_sysctl,
457			    "I", "Battery discharge rate (mA)");
458			SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
459			    "voltage", CTLTYPE_INT | CTLFLAG_RD, sc,
460			    PMU_BATSYSCTL_VOLTAGE | i, pmu_battquery_sysctl,
461			    "I", "Battery voltage (mV)");
462
463			/* Knobs for mental compatibility with ACPI */
464
465			SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
466			    "time", CTLTYPE_INT | CTLFLAG_RD, sc,
467			    PMU_BATSYSCTL_TIME | i, pmu_battquery_sysctl,
468			    "I", "Time Remaining (minutes)");
469			SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
470			    "life", CTLTYPE_INT | CTLFLAG_RD, sc,
471			    PMU_BATSYSCTL_LIFE | i, pmu_battquery_sysctl,
472			    "I", "Capacity remaining (percent)");
473		}
474	}
475
476	/*
477	 * Set up LED interface
478	 */
479
480	sc->sc_leddev = led_create(pmu_set_sleepled, sc, "sleepled");
481
482	/*
483	 * Register RTC
484	 */
485
486	clock_register(dev, 1000);
487
488	/*
489	 * Register power control handler
490	 */
491	EVENTHANDLER_REGISTER(shutdown_final, pmu_shutdown, sc,
492	    SHUTDOWN_PRI_LAST);
493
494	return (bus_generic_attach(dev));
495}
496
497static int
498pmu_detach(device_t dev)
499{
500	struct pmu_softc *sc;
501
502	sc = device_get_softc(dev);
503
504	if (sc->sc_leddev != NULL)
505		led_destroy(sc->sc_leddev);
506
507	bus_teardown_intr(dev, sc->sc_irq, sc->sc_ih);
508	bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqrid, sc->sc_irq);
509	bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_memrid, sc->sc_memr);
510	mtx_destroy(&sc->sc_mutex);
511
512	return (bus_generic_detach(dev));
513}
514
515static uint8_t
516pmu_read_reg(struct pmu_softc *sc, u_int offset)
517{
518	return (bus_read_1(sc->sc_memr, offset));
519}
520
521static void
522pmu_write_reg(struct pmu_softc *sc, u_int offset, uint8_t value)
523{
524	bus_write_1(sc->sc_memr, offset, value);
525}
526
527static int
528pmu_send_byte(struct pmu_softc *sc, uint8_t data)
529{
530
531	pmu_out(sc);
532	pmu_write_reg(sc, vSR, data);
533	pmu_ack_off(sc);
534	/* wait for intr to come up */
535	/* XXX should add a timeout and bail if it expires */
536	do {} while (pmu_intr_state(sc) == 0);
537	pmu_ack_on(sc);
538	do {} while (pmu_intr_state(sc));
539	pmu_ack_on(sc);
540	return 0;
541}
542
543static inline int
544pmu_read_byte(struct pmu_softc *sc, uint8_t *data)
545{
546	volatile uint8_t scratch;
547	pmu_in(sc);
548	scratch = pmu_read_reg(sc, vSR);
549	pmu_ack_off(sc);
550	/* wait for intr to come up */
551	do {} while (pmu_intr_state(sc) == 0);
552	pmu_ack_on(sc);
553	do {} while (pmu_intr_state(sc));
554	*data = pmu_read_reg(sc, vSR);
555	return 0;
556}
557
558static int
559pmu_intr_state(struct pmu_softc *sc)
560{
561	return ((pmu_read_reg(sc, vBufB) & vPB3) == 0);
562}
563
564static int
565pmu_send(void *cookie, int cmd, int length, uint8_t *in_msg, int rlen,
566    uint8_t *out_msg)
567{
568	struct pmu_softc *sc = cookie;
569	int i, rcv_len = -1;
570	uint8_t out_len, intreg;
571
572	intreg = pmu_read_reg(sc, vIER);
573	intreg &= 0x10;
574	pmu_write_reg(sc, vIER, intreg);
575
576	/* wait idle */
577	do {} while (pmu_intr_state(sc));
578
579	/* send command */
580	pmu_send_byte(sc, cmd);
581
582	/* send length if necessary */
583	if (pm_send_cmd_type[cmd] < 0) {
584		pmu_send_byte(sc, length);
585	}
586
587	for (i = 0; i < length; i++) {
588		pmu_send_byte(sc, in_msg[i]);
589	}
590
591	/* see if there's data to read */
592	rcv_len = pm_receive_cmd_type[cmd];
593	if (rcv_len == 0)
594		goto done;
595
596	/* read command */
597	if (rcv_len == 1) {
598		pmu_read_byte(sc, out_msg);
599		goto done;
600	} else
601		out_msg[0] = cmd;
602	if (rcv_len < 0) {
603		pmu_read_byte(sc, &out_len);
604		rcv_len = out_len + 1;
605	}
606	for (i = 1; i < min(rcv_len, rlen); i++)
607		pmu_read_byte(sc, &out_msg[i]);
608
609done:
610	pmu_write_reg(sc, vIER, (intreg == 0) ? 0 : 0x90);
611
612	return rcv_len;
613}
614
615
616static u_int
617pmu_poll(device_t dev)
618{
619	pmu_intr(dev);
620	return (0);
621}
622
623static void
624pmu_in(struct pmu_softc *sc)
625{
626	uint8_t reg;
627
628	reg = pmu_read_reg(sc, vACR);
629	reg &= ~vSR_OUT;
630	reg |= 0x0c;
631	pmu_write_reg(sc, vACR, reg);
632}
633
634static void
635pmu_out(struct pmu_softc *sc)
636{
637	uint8_t reg;
638
639	reg = pmu_read_reg(sc, vACR);
640	reg |= vSR_OUT;
641	reg |= 0x0c;
642	pmu_write_reg(sc, vACR, reg);
643}
644
645static void
646pmu_ack_off(struct pmu_softc *sc)
647{
648	uint8_t reg;
649
650	reg = pmu_read_reg(sc, vBufB);
651	reg &= ~vPB4;
652	pmu_write_reg(sc, vBufB, reg);
653}
654
655static void
656pmu_ack_on(struct pmu_softc *sc)
657{
658	uint8_t reg;
659
660	reg = pmu_read_reg(sc, vBufB);
661	reg |= vPB4;
662	pmu_write_reg(sc, vBufB, reg);
663}
664
665static void
666pmu_intr(void *arg)
667{
668	device_t        dev;
669	struct pmu_softc *sc;
670
671	unsigned int len;
672	uint8_t resp[16];
673	uint8_t junk[16];
674
675        dev = (device_t)arg;
676	sc = device_get_softc(dev);
677
678	mtx_lock(&sc->sc_mutex);
679
680	pmu_write_reg(sc, vIFR, 0x90);	/* Clear 'em */
681	len = pmu_send(sc, PMU_INT_ACK, 0, NULL, 16, resp);
682
683	mtx_unlock(&sc->sc_mutex);
684
685	if ((len < 1) || (resp[1] == 0)) {
686		return;
687	}
688
689	if (resp[1] & PMU_INT_ADB) {
690		/*
691		 * the PMU will turn off autopolling after each command that
692		 * it did not issue, so we assume any but TALK R0 is ours and
693		 * re-enable autopoll here whenever we receive an ACK for a
694		 * non TR0 command.
695		 */
696		mtx_lock(&sc->sc_mutex);
697
698		if ((resp[2] & 0x0f) != (ADB_COMMAND_TALK << 2)) {
699			if (sc->sc_autopoll) {
700				uint8_t cmd[] = {0, PMU_SET_POLL_MASK,
701				    (sc->sc_autopoll >> 8) & 0xff,
702				    sc->sc_autopoll & 0xff};
703
704				pmu_send(sc, PMU_ADB_CMD, 4, cmd, 16, junk);
705			}
706		}
707
708		mtx_unlock(&sc->sc_mutex);
709
710		adb_receive_raw_packet(sc->adb_bus,resp[1],resp[2],
711			len - 3,&resp[3]);
712	}
713	if (resp[1] & PMU_INT_ENVIRONMENT) {
714		/* if the lid was just closed, notify devd. */
715		if ((resp[2] & PMU_ENV_LID_CLOSED) && (!sc->lid_closed)) {
716			sc->lid_closed = 1;
717			if (devctl_process_running())
718				devctl_notify("PMU", "lid", "close", NULL);
719		}
720		else if (!(resp[2] & PMU_ENV_LID_CLOSED) && (sc->lid_closed)) {
721			/* if the lid was just opened, notify devd. */
722			if (devctl_process_running())
723				devctl_notify("PMU", "lid", "open", NULL);
724			sc->lid_closed = 0;
725		}
726	}
727}
728
729static u_int
730pmu_adb_send(device_t dev, u_char command_byte, int len, u_char *data,
731    u_char poll)
732{
733	struct pmu_softc *sc = device_get_softc(dev);
734	int i,replen;
735	uint8_t packet[16], resp[16];
736
737	/* construct an ADB command packet and send it */
738
739	packet[0] = command_byte;
740
741	packet[1] = 0;
742	packet[2] = len;
743	for (i = 0; i < len; i++)
744		packet[i + 3] = data[i];
745
746	mtx_lock(&sc->sc_mutex);
747	replen = pmu_send(sc, PMU_ADB_CMD, len + 3, packet, 16, resp);
748	mtx_unlock(&sc->sc_mutex);
749
750	if (poll)
751		pmu_poll(dev);
752
753	return 0;
754}
755
756static u_int
757pmu_adb_autopoll(device_t dev, uint16_t mask)
758{
759	struct pmu_softc *sc = device_get_softc(dev);
760
761	/* magical incantation to re-enable autopolling */
762	uint8_t cmd[] = {0, PMU_SET_POLL_MASK, (mask >> 8) & 0xff, mask & 0xff};
763	uint8_t resp[16];
764
765	mtx_lock(&sc->sc_mutex);
766
767	if (sc->sc_autopoll == mask) {
768		mtx_unlock(&sc->sc_mutex);
769		return 0;
770	}
771
772	sc->sc_autopoll = mask & 0xffff;
773
774	if (mask)
775		pmu_send(sc, PMU_ADB_CMD, 4, cmd, 16, resp);
776	else
777		pmu_send(sc, PMU_ADB_POLL_OFF, 0, NULL, 16, resp);
778
779	mtx_unlock(&sc->sc_mutex);
780
781	return 0;
782}
783
784static void
785pmu_shutdown(void *xsc, int howto)
786{
787	struct pmu_softc *sc = xsc;
788	uint8_t cmd[] = {'M', 'A', 'T', 'T'};
789
790	if (howto & RB_HALT)
791		pmu_send(sc, PMU_POWER_OFF, 4, cmd, 0, NULL);
792	else
793		pmu_send(sc, PMU_RESET_CPU, 0, NULL, 0, NULL);
794
795	for (;;);
796}
797
798static void
799pmu_set_sleepled(void *xsc, int onoff)
800{
801	struct pmu_softc *sc = xsc;
802	uint8_t cmd[] = {4, 0, 0};
803
804	cmd[2] = onoff;
805
806	mtx_lock(&sc->sc_mutex);
807	pmu_send(sc, PMU_SET_SLEEPLED, 3, cmd, 0, NULL);
808	mtx_unlock(&sc->sc_mutex);
809}
810
811static int
812pmu_server_mode(SYSCTL_HANDLER_ARGS)
813{
814	struct pmu_softc *sc = arg1;
815
816	u_int server_mode = 0;
817	uint8_t getcmd[] = {PMU_PWR_GET_POWERUP_EVENTS};
818	uint8_t setcmd[] = {0, 0, PMU_PWR_WAKEUP_AC_INSERT};
819	uint8_t resp[3];
820	int error, len;
821
822	mtx_lock(&sc->sc_mutex);
823	len = pmu_send(sc, PMU_POWER_EVENTS, 1, getcmd, 3, resp);
824	mtx_unlock(&sc->sc_mutex);
825
826	if (len == 3)
827		server_mode = (resp[2] & PMU_PWR_WAKEUP_AC_INSERT) ? 1 : 0;
828
829	error = sysctl_handle_int(oidp, &server_mode, 0, req);
830
831	if (len != 3)
832		return (EINVAL);
833
834	if (error || !req->newptr)
835		return (error);
836
837	if (server_mode == 1)
838		setcmd[0] = PMU_PWR_SET_POWERUP_EVENTS;
839	else if (server_mode == 0)
840		setcmd[0] = PMU_PWR_CLR_POWERUP_EVENTS;
841	else
842		return (EINVAL);
843
844	setcmd[1] = resp[1];
845
846	mtx_lock(&sc->sc_mutex);
847	pmu_send(sc, PMU_POWER_EVENTS, 3, setcmd, 2, resp);
848	mtx_unlock(&sc->sc_mutex);
849
850	return (0);
851}
852
853static int
854pmu_query_battery(struct pmu_softc *sc, int batt, struct pmu_battstate *info)
855{
856	uint8_t reg;
857	uint8_t resp[16];
858	int len;
859
860	reg = batt + 1;
861
862	mtx_lock(&sc->sc_mutex);
863	len = pmu_send(sc, PMU_SMART_BATTERY_STATE, 1, &reg, 16, resp);
864	mtx_unlock(&sc->sc_mutex);
865
866	if (len < 3)
867		return (-1);
868
869	/* All PMU battery info replies share a common header:
870	 * Byte 1	Payload Format
871	 * Byte 2	Battery Flags
872	 */
873
874	info->state = resp[2];
875
876	switch (resp[1]) {
877	case 3:
878	case 4:
879		/*
880		 * Formats 3 and 4 appear to be the same:
881		 * Byte 3	Charge
882		 * Byte 4	Max Charge
883		 * Byte 5	Current
884		 * Byte 6	Voltage
885		 */
886
887		info->charge = resp[3];
888		info->maxcharge = resp[4];
889		/* Current can be positive or negative */
890		info->current = (int8_t)resp[5];
891		info->voltage = resp[6];
892		break;
893	case 5:
894		/*
895		 * Formats 5 is a wider version of formats 3 and 4
896		 * Byte 3-4	Charge
897		 * Byte 5-6	Max Charge
898		 * Byte 7-8	Current
899		 * Byte 9-10	Voltage
900		 */
901
902		info->charge = (resp[3] << 8) | resp[4];
903		info->maxcharge = (resp[5] << 8) | resp[6];
904		/* Current can be positive or negative */
905		info->current = (int16_t)((resp[7] << 8) | resp[8]);
906		info->voltage = (resp[9] << 8) | resp[10];
907		break;
908	default:
909		device_printf(sc->sc_dev, "Unknown battery info format (%d)!\n",
910		    resp[1]);
911		return (-1);
912	}
913
914	return (0);
915}
916
917static int
918pmu_acline_state(SYSCTL_HANDLER_ARGS)
919{
920	struct pmu_softc *sc;
921	struct pmu_battstate batt;
922	int error, result;
923
924	sc = arg1;
925
926	/* The PMU treats the AC line status as a property of the battery */
927	error = pmu_query_battery(sc, 0, &batt);
928
929	if (error != 0)
930		return (error);
931
932	result = (batt.state & PMU_PWR_AC_PRESENT) ? 1 : 0;
933	error = sysctl_handle_int(oidp, &result, 0, req);
934
935	return (error);
936}
937
938static int
939pmu_battquery_sysctl(SYSCTL_HANDLER_ARGS)
940{
941	struct pmu_softc *sc;
942	struct pmu_battstate batt;
943	int error, result;
944
945	sc = arg1;
946
947	error = pmu_query_battery(sc, arg2 & 0x00ff, &batt);
948
949	if (error != 0)
950		return (error);
951
952	switch (arg2 & 0xff00) {
953	case PMU_BATSYSCTL_PRESENT:
954		result = (batt.state & PMU_PWR_BATT_PRESENT) ? 1 : 0;
955		break;
956	case PMU_BATSYSCTL_CHARGING:
957		result = (batt.state & PMU_PWR_BATT_CHARGING) ? 1 : 0;
958		break;
959	case PMU_BATSYSCTL_CHARGE:
960		result = batt.charge;
961		break;
962	case PMU_BATSYSCTL_MAXCHARGE:
963		result = batt.maxcharge;
964		break;
965	case PMU_BATSYSCTL_CURRENT:
966		result = batt.current;
967		break;
968	case PMU_BATSYSCTL_VOLTAGE:
969		result = batt.voltage;
970		break;
971	case PMU_BATSYSCTL_TIME:
972		/* Time remaining until full charge/discharge, in minutes */
973
974		if (batt.current >= 0)
975			result = (batt.maxcharge - batt.charge) /* mAh */ * 60
976			    / batt.current /* mA */;
977		else
978			result = (batt.charge /* mAh */ * 60)
979			    / (-batt.current /* mA */);
980		break;
981	case PMU_BATSYSCTL_LIFE:
982		/* Battery charge fraction, in percent */
983		result = (batt.charge * 100) / batt.maxcharge;
984		break;
985	default:
986		/* This should never happen */
987		result = -1;
988	};
989
990	error = sysctl_handle_int(oidp, &result, 0, req);
991
992	return (error);
993}
994
995#define DIFF19041970	2082844800
996
997static int
998pmu_gettime(device_t dev, struct timespec *ts)
999{
1000	struct pmu_softc *sc = device_get_softc(dev);
1001	uint8_t resp[16];
1002	uint32_t sec;
1003
1004	mtx_lock(&sc->sc_mutex);
1005	pmu_send(sc, PMU_READ_RTC, 0, NULL, 16, resp);
1006	mtx_unlock(&sc->sc_mutex);
1007
1008	memcpy(&sec, &resp[1], 4);
1009	ts->tv_sec = sec - DIFF19041970;
1010	ts->tv_nsec = 0;
1011
1012	return (0);
1013}
1014
1015static int
1016pmu_settime(device_t dev, struct timespec *ts)
1017{
1018	struct pmu_softc *sc = device_get_softc(dev);
1019	uint32_t sec;
1020
1021	sec = ts->tv_sec + DIFF19041970;
1022
1023	mtx_lock(&sc->sc_mutex);
1024	pmu_send(sc, PMU_SET_RTC, sizeof(sec), (uint8_t *)&sec, 0, NULL);
1025	mtx_unlock(&sc->sc_mutex);
1026
1027	return (0);
1028}
1029
1030int
1031pmu_set_speed(int low_speed)
1032{
1033	struct pmu_softc *sc;
1034	uint8_t sleepcmd[] = {'W', 'O', 'O', 'F', 0};
1035	uint8_t resp[16];
1036
1037	sc = device_get_softc(pmu);
1038	pmu_write_reg(sc, vIER, 0x10);
1039	spinlock_enter();
1040	mtdec(0x7fffffff);
1041	mb();
1042	mtdec(0x7fffffff);
1043
1044	sleepcmd[4] = low_speed;
1045	pmu_send(sc, PMU_CPU_SPEED, 5, sleepcmd, 16, resp);
1046	unin_chip_sleep(NULL, 1);
1047	platform_sleep();
1048	unin_chip_wake(NULL);
1049
1050	mtdec(1);	/* Force a decrementer exception */
1051	spinlock_exit();
1052	pmu_write_reg(sc, vIER, 0x90);
1053
1054	return (0);
1055}
1056