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