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