Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 28 Oct 2012 21:49:17 -0400
From:      Justin Hibbits <chmeeedalf@gmail.com>
To:        freebsd-ppc@freebsd.org
Subject:   Help on PMU work
Message-ID:  <20121028214917.3500f21e@narn.knownspace>

next in thread | raw e-mail | index | archive | help
--MP_/0OtZeAhMXg1GgqTp+4I7Ns.
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

I'm working on getting PMU sleep and speed control working for at least
the MPC7455-based PowerBooks and running into a snag.  I've got it
changing speed, but it immediately panics.

The method for PMU speed change is as follows:
* Tell the PMU to change PLL inputs
* Save all the needed registers (methinks I missed one or two critical
  ones, but can't figure out which)
* Flush and disable the caches
* Disable NAP and enable SLEEP in HID0
* Sleep via MSR
* PMU asserts #HRESET, and jumps to where you want (write address at
  0x80).
* Recover and restore all the necessary registers
* Go on your merry way.

I'm getting stuck on the "Go on your merry way" part.  When it
recovers, I get a 'panic: null_fetch_syscall_args'.  curthread is the
same going into and coming out of reset/restore, verified with a printf.

Any help tracking this down is greatly appreciated.  I'll be at MeetBSD
with my PowerBook, and hope to get it finished either before then, or
by the time I leave.

- Justin
--MP_/0OtZeAhMXg1GgqTp+4I7Ns.
Content-Type: text/x-patch
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename=pmufreq.diff

Index: sys/powerpc/aim/mp_cpudep.c
===================================================================
--- sys/powerpc/aim/mp_cpudep.c	(revision 241450)
+++ sys/powerpc/aim/mp_cpudep.c	(working copy)
@@ -322,17 +322,13 @@
 		mtspr(SPR_CELL_TSRL, bsp_state[5]);
 
 		break;
-	case MPC7450:
-	case MPC7455:
-	case MPC7457:
-		/* Only MPC745x CPUs have an L3 cache. */
-		reg = mpc745x_l3_enable(bsp_state[3]);
-		
-		/* Fallthrough */
 	case MPC7400:
 	case MPC7410:
 	case MPC7447A:
 	case MPC7448:
+	case MPC7450:
+	case MPC7455:
+	case MPC7457:
 		/* XXX: Program the CPU ID into PIR */
 		__asm __volatile("mtspr 1023,%0" :: "r"(PCPU_GET(cpuid)));
 
@@ -342,6 +338,18 @@
 		mtspr(SPR_HID0, bsp_state[0]); isync();
 		mtspr(SPR_HID1, bsp_state[1]); isync();
 
+		/* Now enable the L3 cache. */
+		switch (vers) {
+		case MPC7450:
+		case MPC7455:
+		case MPC7457:
+			/* Only MPC745x CPUs have an L3 cache. */
+			reg = mpc745x_l3_enable(bsp_state[3]);
+		default:
+			break;
+		}
+		
+		/* Fallthrough */
 		reg = mpc74xx_l2_enable(bsp_state[2]);
 		reg = mpc74xx_l1d_enable();
 		reg = mpc74xx_l1i_enable();
Index: sys/powerpc/powerpc/mp_machdep.c
===================================================================
--- sys/powerpc/powerpc/mp_machdep.c	(revision 241450)
+++ sys/powerpc/powerpc/mp_machdep.c	(working copy)
@@ -53,25 +53,41 @@
 #include <machine/pcb.h>
 #include <machine/platform.h>
 #include <machine/md_var.h>
+#include <machine/setjmp.h>
 #include <machine/smp.h>
 
 #include "pic_if.h"
 
 extern struct pcpu __pcpu[MAXCPU];
 
+extern void *ap_pcpu;
 volatile static int ap_awake;
 volatile static u_int ap_letgo;
-volatile static u_quad_t ap_timebase;
+volatile u_quad_t ap_timebase;
 static u_int ipi_msg_cnt[32];
 static struct mtx ap_boot_mtx;
 struct pcb stoppcbs[MAXCPU];
+int longfault(faultbuf, int);
 
 void
 machdep_ap_bootstrap(void)
 {
+	jmp_buf *restore;
+#ifdef __powerpc64__
+	/* Writing to the time base register is hypervisor-privileged */
+	if (mfmsr() & PSL_HV)
+		mttb(ap_timebase);
+#else
+	mttb(ap_timebase);
+#endif
 	/* Set up important bits on the CPU (HID registers, etc.) */
 	cpudep_ap_setup();
 
+	restore = PCPU_GET(restore);
+	if (restore != NULL) {
+		longjmp(*restore, 1);
+	}
+
 	/* Set PIR */
 	PCPU_SET(pir, mfspr(SPR_PIR));
 	PCPU_SET(awake, 1);
@@ -80,14 +96,7 @@
 	while (ap_letgo == 0)
 		;
 
-	/* Initialize DEC and TB, sync with the BSP values */
-#ifdef __powerpc64__
-	/* Writing to the time base register is hypervisor-privileged */
-	if (mfmsr() & PSL_HV)
-		mttb(ap_timebase);
-#else
-	mttb(ap_timebase);
-#endif
+	/* Initialize DEC, sync with the BSP values */
 	decr_ap_init();
 
 	/* Serialize console output and AP count increment */
@@ -201,11 +210,13 @@
 	struct pcpu *pc;
 	int cpus, timeout;
 
-	if (mp_ncpus <= 1)
+	mtx_init(&ap_boot_mtx, "ap boot", NULL, MTX_SPIN);
+
+	if (mp_ncpus <= 1) {
+		atomic_store_rel_int(&ap_letgo, 1);
 		return;
+	}
 
-	mtx_init(&ap_boot_mtx, "ap boot", NULL, MTX_SPIN);
-
 	cpus = 0;
 	smp_cpus = 0;
 	STAILQ_FOREACH(pc, &cpuhead, pc_allcpu) {
Index: sys/powerpc/cpufreq/pmufreq.c
===================================================================
--- sys/powerpc/cpufreq/pmufreq.c	(revision 0)
+++ sys/powerpc/cpufreq/pmufreq.c	(working copy)
@@ -0,0 +1,225 @@
+/*-
+ * Copyright (c) 2011 Justin Hibbits
+ * Copyright (c) 2009 Nathan Whitehorn
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/powerpc/cpufreq/pmufreq.c 217065 2011-01-06 20:19:01Z andreast $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/cpu.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/openfirm.h>
+
+#include "cpufreq_if.h"
+#include "powerpc/powermac/pmuvar.h"
+
+struct pmufreq_softc {
+	device_t dev;
+	uint32_t minfreq;
+	uint32_t maxfreq;
+	uint32_t curfreq;
+};
+
+static void	pmufreq_identify(driver_t *driver, device_t parent);
+static int	pmufreq_probe(device_t dev);
+static int	pmufreq_attach(device_t dev);
+static int	pmufreq_settings(device_t dev, struct cf_setting *sets, int *count);
+static int	pmufreq_set(device_t dev, const struct cf_setting *set);
+static int	pmufreq_get(device_t dev, struct cf_setting *set);
+static int	pmufreq_type(device_t dev, int *type);
+
+static device_method_t pmufreq_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_identify,	pmufreq_identify),
+	DEVMETHOD(device_probe,		pmufreq_probe),
+	DEVMETHOD(device_attach,	pmufreq_attach),
+
+	/* cpufreq interface */
+	DEVMETHOD(cpufreq_drv_set,	pmufreq_set),
+	DEVMETHOD(cpufreq_drv_get,	pmufreq_get),
+	DEVMETHOD(cpufreq_drv_type,	pmufreq_type),
+	DEVMETHOD(cpufreq_drv_settings,	pmufreq_settings),
+
+	{0, 0}
+};
+
+static driver_t pmufreq_driver = {
+	"pmufreq",
+	pmufreq_methods,
+	sizeof(struct pmufreq_softc)
+};
+
+static devclass_t pmufreq_devclass;
+DRIVER_MODULE(pmufreq, cpu, pmufreq_driver, pmufreq_devclass, 0, 0);
+
+static void
+pmufreq_identify(driver_t *driver, device_t parent)
+{
+	uint16_t vers;
+	vers = mfpvr() >> 16;
+
+	/* Check for an MPC7455 CPU */
+	switch (vers) {
+		case MPC7455:
+			break;
+		default:
+			return;
+	}
+
+	/* Make sure we're not being doubly invoked. */
+	if (device_find_child(parent, "pmufreq", -1) != NULL)
+		return;
+
+	/*
+	 * We attach a child for every CPU since settings need to
+	 * be performed on every CPU in the SMP case.
+	 */
+	if (BUS_ADD_CHILD(parent, 10, "pmufreq", -1) == NULL)
+		device_printf(parent, "add pmufreq child failed\n");
+}
+
+static int
+pmufreq_probe(device_t dev)
+{
+	uint32_t min_freq;
+	struct pmufreq_softc *sc;
+	phandle_t node;
+
+	if (resource_disabled("pmufreq", 0))
+		return (ENXIO);
+
+	sc = device_get_softc(dev);
+	node = ofw_bus_get_node(device_get_parent(dev));
+	/*
+	 * A scalable MPC7455 has min-clock-frequency/max-clock-frequency as OFW
+	 * properties of the 'cpu' node.
+	 */
+	if (OF_getprop(node, "min-clock-frequency", &min_freq, sizeof(min_freq)) == -1)
+		return (ENXIO);
+	device_set_desc(dev, "PMU-based frequency scaling");
+	return (0);
+}
+
+static int
+pmufreq_attach(device_t dev)
+{
+	struct pmufreq_softc *sc;
+	phandle_t node;
+
+	sc = device_get_softc(dev);
+	sc->dev = dev;
+
+	node = ofw_bus_get_node(device_get_parent(dev));
+	OF_getprop(node, "min-clock-frequency", &sc->minfreq, sizeof(sc->minfreq));
+	OF_getprop(node, "max-clock-frequency", &sc->maxfreq, sizeof(sc->maxfreq));
+	OF_getprop(node, "rounded-clock-frequency", &sc->curfreq, sizeof(sc->curfreq));
+	sc->minfreq /= 1000000;
+	sc->maxfreq /= 1000000;
+	sc->curfreq /= 1000000;
+
+	cpufreq_register(dev);
+	return (0);
+}
+
+static int
+pmufreq_settings(device_t dev, struct cf_setting *sets, int *count)
+{
+	struct pmufreq_softc *sc;
+
+	sc = device_get_softc(dev);
+	if (sets == NULL || count == NULL)
+		return (EINVAL);
+	if (*count < 2)
+		return (E2BIG);
+
+	/* Return a list of valid settings for this driver. */
+	memset(sets, CPUFREQ_VAL_UNKNOWN, sizeof(*sets) * 2);
+
+	sets[0].freq = sc->maxfreq; sets[0].dev = dev;
+	sets[1].freq = sc->minfreq; sets[1].dev = dev;
+	/* Set high latency for CPU frequency changes, it's a tedious process. */
+	sets[0].lat = 1000000;
+	sets[1].lat = 1000000;
+	*count = 2;
+
+	return (0);
+}
+
+static int
+pmufreq_set(device_t dev, const struct cf_setting *set)
+{
+	struct pmufreq_softc *sc;
+	int speed_sel;
+	int error;
+
+	if (set == NULL)
+		return (EINVAL);
+
+	sc = device_get_softc(dev);
+
+	if (set->freq == sc->maxfreq)
+		speed_sel = 1;
+	else
+		speed_sel = 0;
+
+	error = pmu_set_speed(speed_sel);
+	if (error == 0)
+		sc->curfreq = set->freq;
+
+	return error;
+}
+
+static int
+pmufreq_get(device_t dev, struct cf_setting *set)
+{
+	struct pmufreq_softc *sc;
+
+	if (set == NULL)
+		return (EINVAL);
+	sc = device_get_softc(dev);
+
+	set->freq = sc->curfreq;
+	set->dev = dev;
+
+	return (0);
+}
+
+static int
+pmufreq_type(device_t dev, int *type)
+{
+
+	if (type == NULL)
+		return (EINVAL);
+
+	*type = CPUFREQ_TYPE_ABSOLUTE;
+	return (0);
+}
+
Index: sys/conf/files.powerpc
===================================================================
--- sys/conf/files.powerpc	(revision 241450)
+++ sys/conf/files.powerpc	(working copy)
@@ -115,6 +115,7 @@
 powerpc/booke/vm_machdep.c	optional	booke
 powerpc/cpufreq/dfs.c		optional	cpufreq
 powerpc/cpufreq/pcr.c		optional	cpufreq aim
+powerpc/cpufreq/pmufreq.c	optional	cpufreq aim
 powerpc/fpu/fpu_add.c		optional	fpu_emu powerpc
 powerpc/fpu/fpu_compare.c	optional	fpu_emu powerpc
 powerpc/fpu/fpu_div.c		optional	fpu_emu powerpc
Index: sys/powerpc/powermac/viareg.h
===================================================================
--- sys/powerpc/powermac/viareg.h	(revision 241450)
+++ sys/powerpc/powermac/viareg.h	(working copy)
@@ -33,6 +33,8 @@
 #define vBufA		0x0200	/* register A */
 #define vDirB		0x0400	/* data direction register */
 #define vDirA		0x0600	/* data direction register */
+#define vT1C		0x0800	/* Timer 1 counter Lo */
+#define vT1CH		0x0a00	/* Timer 1 counter Hi */
 #define vSR		0x1400	/* shift register */
 #define vACR		0x1600	/* aux control register */
 #define vPCR		0x1800	/* peripheral control register */
Index: sys/powerpc/powermac/uninorth.c
===================================================================
--- sys/powerpc/powermac/uninorth.c	(revision 241450)
+++ sys/powerpc/powermac/uninorth.c	(working copy)
@@ -65,6 +65,8 @@
 
 static int  unin_chip_probe(device_t);
 static int  unin_chip_attach(device_t);
+static int  unin_chip_suspend(device_t);
+//static int  unin_chip_resume(device_t);
 
 /*
  * Bus interface.
@@ -102,6 +104,8 @@
 	/* Device interface */
 	DEVMETHOD(device_probe,         unin_chip_probe),
 	DEVMETHOD(device_attach,        unin_chip_attach),
+	DEVMETHOD(device_suspend,	unin_chip_suspend),
+	DEVMETHOD(device_resume,	unin_chip_resume),
 
 	/* Bus interface */
 	DEVMETHOD(bus_print_child,      unin_chip_print_child),
@@ -136,6 +140,13 @@
 
 static devclass_t	unin_chip_devclass;
 
+/*
+ * Assume there is only one unin chip in a PowerMac, so that pmu.c functions can
+ * suspend the chip after the whole rest of the device tree is suspended, not
+ * earlier.
+ */
+static device_t		unin_chip;
+
 DRIVER_MODULE(unin, nexus, unin_chip_driver, unin_chip_devclass, 0, 0);
 
 /*
@@ -210,31 +221,30 @@
 }
 
 static void
-unin_enable_gmac(device_t dev)
+unin_update_reg(device_t dev, uint32_t regoff, uint32_t set, uint32_t clr)
 {
-	volatile u_int *clkreg;
+	volatile u_int *reg;
 	struct unin_chip_softc *sc;
 	u_int32_t tmpl;
 
 	sc = device_get_softc(dev);
-	clkreg = (void *)(sc->sc_addr + UNIN_CLOCKCNTL);
-	tmpl = inl(clkreg);
-	tmpl |= UNIN_CLOCKCNTL_GMAC;
-	outl(clkreg, tmpl);
+	reg = (void *)(sc->sc_addr + regoff);
+	tmpl = inl(reg);
+	tmpl &= ~clr;
+	tmpl |= set;
+	outl(reg, tmpl);
 }
 
 static void
+unin_enable_gmac(device_t dev)
+{
+	unin_update_reg(dev, UNIN_CLOCKCNTL, UNIN_CLOCKCNTL_GMAC, 0);
+}
+
+static void
 unin_enable_mpic(device_t dev)
 {
-	volatile u_int *toggle;
-	struct unin_chip_softc *sc;
-	u_int32_t tmpl;
-
-	sc = device_get_softc(dev);
-	toggle = (void *)(sc->sc_addr + UNIN_TOGGLE_REG);
-	tmpl = inl(toggle);
-	tmpl |= UNIN_MPIC_RESET | UNIN_MPIC_OUTPUT_ENABLE;
-	outl(toggle, tmpl);
+	unin_update_reg(dev, UNIN_TOGGLE_REG, UNIN_MPIC_RESET | UNIN_MPIC_OUTPUT_ENABLE, 0);
 }
 
 static int
@@ -301,6 +311,9 @@
 		return (error);
 	}
 
+	if (unin_chip == NULL)
+		unin_chip = dev;
+
         /*
 	 * Iterate through the sub-devices
 	 */
@@ -621,3 +634,38 @@
 	return (&dinfo->udi_obdinfo);
 }
 
+static int  unin_chip_suspend(device_t dev)
+{
+	int error;
+
+	error = bus_generic_suspend(dev);
+	return 0;
+}
+
+int  unin_chip_resume(device_t dev)
+{
+	if (dev == NULL)
+		dev = unin_chip;
+	unin_update_reg(dev, UNIN_PWR_MGMT, UNIN_PWR_NORMAL, UNIN_PWR_MASK);
+	DELAY(10);
+	unin_update_reg(dev, UNIN_HWINIT_STATE, UNIN_RUNNING, 0);
+	DELAY(100);
+
+	bus_generic_resume(dev);
+	return (0);
+}
+
+int unin_chip_sleep(device_t dev, int idle)
+{
+	if (dev == NULL)
+		dev = unin_chip;
+
+	unin_update_reg(dev, UNIN_HWINIT_STATE, UNIN_SLEEPING, 0);
+	DELAY(10);
+	if (idle)
+		unin_update_reg(dev, UNIN_PWR_MGMT, UNIN_PWR_IDLE2, UNIN_PWR_MASK);
+	else
+		unin_update_reg(dev, UNIN_PWR_MGMT, UNIN_PWR_SLEEP, UNIN_PWR_MASK);
+	DELAY(10);
+	return (0);
+}
Index: sys/powerpc/powermac/pmuvar.h
===================================================================
--- sys/powerpc/powermac/pmuvar.h	(revision 241450)
+++ sys/powerpc/powermac/pmuvar.h	(working copy)
@@ -161,6 +161,7 @@
 	int		sc_batteries;
 	struct cdev	*sc_leddev;
 	int	lid_closed;
+	uint8_t		saved_regs[9];
 };
 
 struct pmu_battstate {
@@ -172,4 +173,6 @@
 	int voltage;
 };
 
+int pmu_set_speed(int high_speed);
+
 #endif /* PMUVAR_H */
Index: sys/powerpc/powermac/platform_powermac.c
===================================================================
--- sys/powerpc/powermac/platform_powermac.c	(revision 241450)
+++ sys/powerpc/powermac/platform_powermac.c	(working copy)
@@ -280,6 +280,97 @@
 #endif
 }
 
+/* From p3-53 of the MPC7450 RISC Microprocessor Family Reference Manual */
+void
+flush_disable_caches(void)
+{
+	register_t msr;
+	register_t msscr0;
+	register_t cache_reg;
+	volatile uint32_t *romp;
+	uint32_t temp;
+	int i;
+	int x;
+
+	msr = mfmsr();
+	powerpc_sync();
+	mtmsr(msr & ~(PSL_EE | PSL_DR));
+	msscr0 = mfspr(SPR_MSSCR0);
+	msscr0 &= ~MSSCR0_L2PFE;
+	mtspr(SPR_MSSCR0, msscr0);
+	powerpc_sync();
+	isync();
+	__asm__ __volatile__("dssall; sync");
+	powerpc_sync();
+	isync();
+	__asm__ __volatile__("dcbf 0,%0" :: "r"(0));
+	__asm__ __volatile__("dcbf 0,%0" :: "r"(0));
+	__asm__ __volatile__("dcbf 0,%0" :: "r"(0));
+
+	/* Lock the L1 Data cache. */
+	mtspr(SPR_LDSTCR, mfspr(SPR_LDSTCR) | 0xFF);
+	powerpc_sync();
+	isync();
+
+	mtspr(SPR_LDSTCR, 0);
+
+	romp = (uint32_t *)0xfff00000;
+	x = 0xfe;
+
+	for (; x != 0xff;) {
+		mtspr(SPR_LDSTCR, x);
+		for (i = 0; i < 128; i++) {
+			temp = *romp;
+			romp += 32/sizeof(*romp);
+		}
+		x = ((x << 1) | 1) & 0xff;
+	}
+
+	cache_reg = mfspr(SPR_L2CR);
+	if (cache_reg & L2CR_L2E) {
+		cache_reg &= ~(L2CR_L2IO_7450 | L2CR_L2DO_7450);
+		mtspr(SPR_L2CR, cache_reg);
+		powerpc_sync();
+		mtspr(SPR_L2CR, cache_reg | L2CR_L2HWF);
+		while (mfspr(SPR_L2CR) & L2CR_L2HWF)
+			; /* Busy wait for cache to flush */
+		powerpc_sync();
+		cache_reg &= ~L2CR_L2E;
+		mtspr(SPR_L2CR, cache_reg);
+		powerpc_sync();
+		mtspr(SPR_L2CR, cache_reg | L2CR_L2I);
+		powerpc_sync();
+		while (mfspr(SPR_L2CR) & L2CR_L2I)
+			; /* Busy wait for L2 cache invalidate */
+		powerpc_sync();
+	}
+
+	cache_reg = mfspr(SPR_L3CR);
+	if (cache_reg & L3CR_L3E) {
+		cache_reg &= ~(L3CR_L3IO_7450 | L3CR_L3DO_7450);
+		mtspr(SPR_L3CR, cache_reg);
+		powerpc_sync();
+		mtspr(SPR_L3CR, cache_reg | L3CR_L3HWF);
+		while (mfspr(SPR_L3CR) & L3CR_L3HWF)
+			; /* Busy wait for cache to flush */
+		powerpc_sync();
+		cache_reg &= ~L3CR_L3E;
+		mtspr(SPR_L3CR, cache_reg);
+		powerpc_sync();
+		mtspr(SPR_L3CR, cache_reg | L3CR_L3I);
+		powerpc_sync();
+		while (mfspr(SPR_L3CR) & L3CR_L3I)
+			; /* Busy wait for L3 cache invalidate */
+		powerpc_sync();
+	}
+
+	mtspr(SPR_HID0, mfspr(SPR_HID0) & ~HID0_DCE);
+	powerpc_sync();
+	isync();
+
+	mtmsr(msr);
+}
+
 static void
 powermac_reset(platform_t platform)
 {
Index: sys/powerpc/powermac/pmu.c
===================================================================
--- sys/powerpc/powermac/pmu.c	(revision 241450)
+++ sys/powerpc/powermac/pmu.c	(working copy)
@@ -44,10 +44,14 @@
 #include <dev/led/led.h>
 
 #include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/hid.h>
 #include <machine/intr_machdep.h>
 #include <machine/md_var.h>
+#include <machine/pcb.h>
 #include <machine/pio.h>
 #include <machine/resource.h>
+#include <machine/setjmp.h>
 
 #include <vm/vm.h>
 #include <vm/pmap.h>
@@ -60,6 +64,10 @@
 #include "pmuvar.h"
 #include "viareg.h"
 
+#define PMU_DEFAULTS	PMU_INT_TICK | PMU_INT_ADB | \
+	PMU_INT_PCEJECT | PMU_INT_SNDBRT | \
+	PMU_INT_BATTERY | PMU_INT_ENVIRONMENT
+
 /*
  * Bus interface
  */
@@ -89,10 +97,13 @@
 static void	pmu_shutdown(void *xsc, int howto);
 static void	pmu_set_sleepled(void *xsc, int onoff);
 static int	pmu_server_mode(SYSCTL_HANDLER_ARGS);
+static int	pmu_sleep(SYSCTL_HANDLER_ARGS);
 static int	pmu_acline_state(SYSCTL_HANDLER_ARGS);
 static int	pmu_query_battery(struct pmu_softc *sc, int batt, 
 		    struct pmu_battstate *info);
 static int	pmu_battquery_sysctl(SYSCTL_HANDLER_ARGS);
+static void pmu_restore_state(struct pmu_softc *sc);
+static void pmu_save_state(struct pmu_softc *sc);
 
 /*
  * List of battery-related sysctls we might ask for
@@ -193,7 +204,7 @@
 	0x02,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   -1,   -1,
 	0x01, 0x01, 0x01,   -1,   -1,   -1,   -1,   -1,
-	0x00, 0x00,   -1,   -1,   -1,   -1, 0x04, 0x04,
+	0x00, 0x00,   -1,   -1,   -1, 0x05, 0x04, 0x04,
 	0x04,   -1, 0x00,   -1,   -1,   -1,   -1,   -1,
 	0x00,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
 	0x01, 0x02,   -1,   -1,   -1,   -1,   -1,   -1,
@@ -229,7 +240,7 @@
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 	0x04, 0x04, 0x03, 0x09,   -1,   -1,   -1,   -1,
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	  -1,   -1,   -1,   -1,   -1,   -1, 0x01, 0x01,
+	  -1,   -1,   -1,   -1,   -1, 0x01, 0x01, 0x01,
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 	0x06,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -357,12 +368,13 @@
 
 	/* Init PMU */
 
-	reg = PMU_INT_TICK | PMU_INT_ADB | PMU_INT_PCEJECT | PMU_INT_SNDBRT;
-	reg |= PMU_INT_BATTERY;
-	reg |= PMU_INT_ENVIRONMENT;
+	pmu_write_reg(sc, vBufB, pmu_read_reg(sc, vBufB) | vPB4);
+	pmu_write_reg(sc, vDirB, (pmu_read_reg(sc, vDirB) | vPB4) & ~vPB3);
+
+	reg = PMU_DEFAULTS;
 	pmu_send(sc, PMU_SET_IMASK, 1, &reg, 16, resp);
 
-	pmu_write_reg(sc, vIER, 0x90); /* make sure VIA interrupts are on */
+	pmu_write_reg(sc, vIER, 0x94); /* make sure VIA interrupts are on */
 
 	pmu_send(sc, PMU_SYSTEM_READY, 1, cmd, 16, resp);
 	pmu_send(sc, PMU_GET_VERSION, 1, cmd, 16, resp);
@@ -407,6 +419,10 @@
 	    "server_mode", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
 	    pmu_server_mode, "I", "Enable reboot after power failure");
 
+	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+	    "sleep", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
+	    pmu_sleep, "I", "Put the machine to sleep");
+
 	if (sc->sc_batteries > 0) {
 		struct sysctl_oid *oid, *battroot;
 		char battnum[2];
@@ -464,6 +480,7 @@
 		}
 	}
 
+	sc->lid_closed = 0;
 	/*
 	 * Set up LED interface
 	 */
@@ -515,6 +532,34 @@
 	bus_write_1(sc->sc_memr, offset, value);
 }
 
+static void
+pmu_save_state(struct pmu_softc *sc)
+{
+	sc->saved_regs[0] = pmu_read_reg(sc, vBufA);
+	sc->saved_regs[1] = pmu_read_reg(sc, vDirA);
+	sc->saved_regs[2] = pmu_read_reg(sc, vBufB);
+	sc->saved_regs[3] = pmu_read_reg(sc, vDirB);
+	sc->saved_regs[4] = pmu_read_reg(sc, vPCR);
+	sc->saved_regs[5] = pmu_read_reg(sc, vACR);
+	sc->saved_regs[6] = pmu_read_reg(sc, vIER);
+	sc->saved_regs[7] = pmu_read_reg(sc, vT1C);
+	sc->saved_regs[8] = pmu_read_reg(sc, vT1CH);
+}
+
+static void
+pmu_restore_state(struct pmu_softc *sc)
+{
+	pmu_write_reg(sc, vBufA, sc->saved_regs[0]);
+	pmu_write_reg(sc, vDirA, sc->saved_regs[1]);
+	pmu_write_reg(sc, vBufB, sc->saved_regs[2]);
+	pmu_write_reg(sc, vDirB, sc->saved_regs[3]);
+	pmu_write_reg(sc, vPCR, sc->saved_regs[4]);
+	pmu_write_reg(sc, vACR, sc->saved_regs[5]);
+	pmu_write_reg(sc, vIER, sc->saved_regs[6]);
+	pmu_write_reg(sc, vT1C, sc->saved_regs[7]);
+	pmu_write_reg(sc, vT1CH, sc->saved_regs[8]);
+}
+
 static int
 pmu_send_byte(struct pmu_softc *sc, uint8_t data)
 {
@@ -1018,3 +1063,145 @@
 	return (0);
 }
 
+static jmp_buf resetjb;
+static register_t sprgs[4];
+static register_t srrs[2];
+extern void *ap_pcpu;
+extern int setfault(faultbuf);
+extern int unin_chip_sleep(device_t dev, int idle);
+extern int unin_chip_resume(device_t dev);
+extern u_quad_t ap_timebase;
+extern void move_sp(uint32_t *newptr);
+extern void pmu_sleep_int(void);
+extern void low_sleep_handler(void);
+
+void pmu_sleep_int(void)
+{
+	register_t hid0;
+	register_t msr;
+	register_t saved_msr;
+	ap_pcpu = pcpup;
+	PCPU_SET(restore, &resetjb);
+
+	*(unsigned long *)0x80 = 0x100;
+	saved_msr = mfmsr();
+	ap_timebase = mftb();
+	flush_disable_caches();
+	if (setjmp(resetjb) == 0) {
+		sprgs[0] = mfspr(SPR_SPRG0);
+		sprgs[1] = mfspr(SPR_SPRG1);
+		sprgs[2] = mfspr(SPR_SPRG2);
+		sprgs[3] = mfspr(SPR_SPRG3);
+		srrs[0] = mfspr(SPR_SRR0);
+		srrs[1] = mfspr(SPR_SRR1);
+		hid0 = mfspr(SPR_HID0);
+		hid0 = (hid0 & ~(HID0_DOZE | HID0_NAP)) | HID0_SLEEP;
+		powerpc_sync();
+		isync();
+		mtspr(SPR_HID0, hid0);
+		powerpc_sync();
+
+		msr = mfmsr() | PSL_POW;
+		while (1)
+			mtmsr(msr);
+	}
+	mtspr(SPR_SPRG0, sprgs[0]);
+	mtspr(SPR_SPRG1, sprgs[1]);
+	mtspr(SPR_SPRG2, sprgs[2]);
+	mtspr(SPR_SPRG3, sprgs[3]);
+	mtspr(SPR_SRR0, srrs[0]);
+	mtspr(SPR_SRR1, srrs[1]);
+	mtmsr(saved_msr);
+	powerpc_sync();
+}
+
+static int
+pmu_sleep(SYSCTL_HANDLER_ARGS)
+{
+	u_int sleep = 0;
+	int error;
+	struct pmu_softc *sc = arg1;
+	uint8_t clrcmd[] = {PMU_PWR_CLR_POWERUP_EVENTS, 0xff, 0xff};
+	uint8_t setcmd[] = {PMU_PWR_SET_POWERUP_EVENTS, 0, PMU_PWR_WAKEUP_LID_OPEN|PMU_PWR_WAKEUP_KEY};
+	uint8_t sleepcmd[] = {'M', 'A', 'T', 'T'};
+	uint8_t resp[16];
+	uint8_t reg;
+	uint8_t cmd[2] = {2, 0};
+
+	error = sysctl_handle_int(oidp, &sleep, 0, req);
+
+	if (error || !req->newptr)
+		return (error);
+
+	error = DEVICE_SUSPEND(root_bus);
+	mtx_lock(&sc->sc_mutex);
+	if (error == 0) {
+		mtx_lock(&Giant);
+		spinlock_enter();
+		reg = 0;
+		pmu_send(sc, PMU_SET_IMASK, 1, &reg, 16, resp);
+		pmu_send(sc, PMU_POWER_EVENTS, 3, clrcmd, 16, resp);
+		pmu_send(sc, PMU_POWER_EVENTS, 3, setcmd, 2, resp);
+		pmu_save_state(sc);
+
+		pmu_send(sc, PMU_SLEEP, 4, sleepcmd, 16, resp);
+		unin_chip_sleep(NULL, 0);
+		pmu_sleep_int();
+		unin_chip_resume(NULL);
+
+		pmu_restore_state(sc);
+		pmu_send(sc, PMU_SYSTEM_READY, 1, cmd, 16, resp);
+		reg = PMU_DEFAULTS;
+		pmu_send(sc, PMU_SET_IMASK, 1, &reg, 16, resp);
+		spinlock_exit();
+		mtx_unlock(&Giant);
+	}
+	mtx_unlock(&sc->sc_mutex);
+	printf("failure: %d\n", error);
+	DEVICE_RESUME(root_bus);
+
+	return (error);
+}
+
+int
+pmu_set_speed(int high_speed)
+{
+	struct pmu_softc *sc;
+	uint8_t sleepcmd[] = {'W', 'O', 'O', 'F', 0};
+	uint8_t resp[16];
+	uint8_t reg;
+
+	sc = device_get_softc(pmu);
+	pmu_write_reg(sc, vIER, 0x10);
+	spinlock_enter();
+	mtdec(0x7fffffff);
+	mb();
+	mtdec(0x7fffffff);
+
+	reg = 0;
+
+	/* The PMU speed change command actually uses '1' to denote low-speed. */
+	if (high_speed)
+		sleepcmd[4] = 0;
+	else
+		sleepcmd[4] = 1;
+
+	printf("curthread: %p\n", curthread);
+	printf("srr0: %x\n", mfspr(SPR_SRR0));
+	mtx_lock(&sc->sc_mutex);
+	pmu_send(sc, PMU_CPU_SPEED, 5, sleepcmd, 16, resp);
+	mtx_unlock(&sc->sc_mutex);
+	unin_chip_sleep(NULL, 1);
+	pmu_sleep_int();
+	decr_init(); /* Reset the ns_per_tick to the new frequency */
+	unin_chip_resume(NULL);
+
+	mtdec(1);
+	spinlock_exit();
+	printf("curthread: %p\n", curthread);
+	printf("srr0: %x\n", mfspr(SPR_SRR0));
+	printf("exit from here\n");
+	pmu_write_reg(sc, vIER, 0x90);
+
+	return (0);
+}
Index: sys/powerpc/powermac/macio.c
===================================================================
--- sys/powerpc/powermac/macio.c	(revision 241450)
+++ sys/powerpc/powermac/macio.c	(working copy)
@@ -69,12 +69,17 @@
 	/* FCR registers */
 	int          sc_memrid;
 	struct resource	*sc_memr;
+	int          sc_rev;
+	int          sc_devid;
+	uint32_t     saved_fcrs[6];
 };
 
 static MALLOC_DEFINE(M_MACIO, "macio", "macio device information");
 
 static int  macio_probe(device_t);
 static int  macio_attach(device_t);
+static int  macio_suspend(device_t);
+static int  macio_resume(device_t);
 static int  macio_print_child(device_t dev, device_t child);
 static void macio_probe_nomatch(device_t, device_t);
 static struct   resource *macio_alloc_resource(device_t, device_t, int, int *,
@@ -97,8 +102,8 @@
 	DEVMETHOD(device_attach,        macio_attach),
 	DEVMETHOD(device_detach,        bus_generic_detach),
 	DEVMETHOD(device_shutdown,      bus_generic_shutdown),
-	DEVMETHOD(device_suspend,       bus_generic_suspend),
-	DEVMETHOD(device_resume,        bus_generic_resume),
+	DEVMETHOD(device_suspend,       macio_suspend),
+	DEVMETHOD(device_resume,        macio_resume),
 	
 	/* Bus interface */
 	DEVMETHOD(bus_print_child,      macio_print_child),
@@ -319,6 +324,13 @@
 	}
 
 	/*
+	 * If possible, get the device ID and revision ID.
+	 */
+	OF_getprop(root, "revision-id", &sc->sc_rev, sizeof(sc->sc_rev));
+	OF_getprop(root, "device-id", &sc->sc_devid, sizeof(sc->sc_devid));
+
+
+	/*
 	 * Iterate through the sub-devices
 	 */
 	for (child = OF_child(root); child != 0; child = OF_peer(child)) {
@@ -605,3 +617,140 @@
 	dinfo = device_get_ivars(child);
 	return (&dinfo->mdi_obdinfo);
 }
+
+static int macio_suspend(device_t dev)
+{
+	int error;
+	uint32_t temp;
+	struct macio_softc *sc = device_get_softc(dev);
+
+	error = bus_generic_suspend(dev);
+
+	if (error)
+		return (error);
+
+	sc->saved_fcrs[0] = bus_read_4(sc->sc_memr, KEYLARGO_FCR0);
+	sc->saved_fcrs[1] = bus_read_4(sc->sc_memr, KEYLARGO_FCR1);
+	sc->saved_fcrs[2] = bus_read_4(sc->sc_memr, KEYLARGO_FCR2);
+	sc->saved_fcrs[3] = bus_read_4(sc->sc_memr, KEYLARGO_FCR3);
+
+	temp = bus_read_4(sc->sc_memr, KEYLARGO_FCR0);
+	temp |= FCR0_USB_REF_SUSPEND;
+	temp &= ~(FCR0_SCCA_ENABLE | FCR0_SCCB_ENABLE |
+			FCR0_SCC_CELL_ENABLE | FCR0_IRDA_ENABLE |
+			FCR0_IRDA_CLK32_ENABLE |
+			FCR0_IRDA_CLK19_ENABLE);
+	bus_write_4(sc->sc_memr, KEYLARGO_FCR0, temp);
+	DELAY(1000);
+
+	if (sc->sc_devid == 0x22) {
+		temp = bus_read_4(sc->sc_memr, KEYLARGO_MEDIABAY);
+		temp |= KEYLARGO_MB0_DEV_ENABLE;
+		bus_write_4(sc->sc_memr, KEYLARGO_MEDIABAY, temp);
+	}
+
+	temp = bus_read_4(sc->sc_memr, KEYLARGO_FCR1);
+	temp &= ~(FCR1_AUDIO_SEL_22MCLK | FCR1_AUDIO_CLK_ENABLE |
+			FCR1_AUDIO_CLKOUT_ENABLE | FCR1_AUDIO_CELL_ENABLE |
+			FCR1_I2S0_CELL_ENABLE | FCR1_I2S0_CLK_ENABLE |
+			FCR1_I2S0_ENABLE |
+			FCR1_I2S1_CELL_ENABLE | FCR1_I2S1_CLK_ENABLE |
+			FCR1_I2S1_ENABLE |
+			FCR1_EIDE0_ENABLE | FCR1_EIDE0_RESET | 
+			FCR1_EIDE1_ENABLE | FCR1_EIDE1_RESET |
+			FCR1_UIDE_ENABLE
+		 );
+	bus_write_4(sc->sc_memr, KEYLARGO_FCR1, temp);
+
+	temp = bus_read_4(sc->sc_memr, KEYLARGO_FCR2);
+	temp &= ~FCR2_IOBUS_ENABLE;
+	bus_write_4(sc->sc_memr, KEYLARGO_FCR2, temp);
+
+	temp = bus_read_4(sc->sc_memr, KEYLARGO_FCR3);
+	temp |= (FCR3_SHUTDOWN_PLL_KW6 | FCR3_SHUTDOWN_PLL_KW4 |
+			FCR3_SHUTDOWN_PLL_KW35 | FCR3_SHUTDOWN_PLL_KW12);
+	temp &= ~(FCR3_CLK_66_ENABLE | FCR3_CLK_49_ENABLE |
+			FCR3_CLK_45_ENABLE | FCR3_CLK_31_ENABLE |
+			FCR3_TMR_CLK18_ENABLE | FCR3_I2S1_CLK18_ENABLE |
+			FCR3_I2S0_CLK18_ENABLE | FCR3_VA_CLK16_ENABLE);
+	if (sc->sc_rev >= 2)
+		temp |= (FCR3_SHUTDOWN_PLL_2X | FCR3_SHUTDOWN_PLL_TOTAL);
+	bus_write_4(sc->sc_memr, KEYLARGO_FCR3, temp);
+	/* Delay for a millisecond to let things settle. */
+	temp = bus_read_4(sc->sc_memr, KEYLARGO_FCR0);
+	DELAY(1000);
+
+	return (0);
+}
+
+static int macio_resume(device_t dev)
+{
+	struct macio_softc *sc = device_get_softc(dev);
+
+	bus_write_4(sc->sc_memr, KEYLARGO_FCR0, sc->saved_fcrs[0]);
+	bus_read_4(sc->sc_memr, KEYLARGO_FCR0);
+	DELAY(10);
+	bus_write_4(sc->sc_memr, KEYLARGO_FCR1, sc->saved_fcrs[1]);
+	bus_read_4(sc->sc_memr, KEYLARGO_FCR1);
+	DELAY(10);
+	bus_write_4(sc->sc_memr, KEYLARGO_FCR2, sc->saved_fcrs[2]);
+	bus_read_4(sc->sc_memr, KEYLARGO_FCR2);
+	DELAY(10);
+	bus_write_4(sc->sc_memr, KEYLARGO_FCR3, sc->saved_fcrs[3]);
+	bus_read_4(sc->sc_memr, KEYLARGO_FCR3);
+	DELAY(10);
+	bus_write_4(sc->sc_memr, KEYLARGO_FCR4, sc->saved_fcrs[4]);
+	bus_read_4(sc->sc_memr, KEYLARGO_FCR4);
+	DELAY(10);
+	bus_write_4(sc->sc_memr, KEYLARGO_FCR5, sc->saved_fcrs[5]);
+	bus_read_4(sc->sc_memr, KEYLARGO_FCR5);
+	DELAY(10);
+
+	bus_generic_resume(dev);
+
+	return (0);
+}
+
+int macio_enable_wireless(device_t dev, bool enable)
+{
+	struct macio_softc *sc = device_get_softc(dev);
+
+	uint32_t x;
+
+	if (enable) {
+		x = bus_read_4(sc->sc_memr, KEYLARGO_FCR2);
+		x |= 0x4;
+		bus_write_4(sc->sc_memr, KEYLARGO_FCR2, x);
+
+		/* Enable card slot. */
+		bus_write_1(sc->sc_memr, KEYLARGO_GPIO_BASE + 0x0f, 5);
+		DELAY(1000);
+		bus_write_1(sc->sc_memr, KEYLARGO_GPIO_BASE + 0x0f, 4);
+		DELAY(1000);
+		x = bus_read_4(sc->sc_memr, KEYLARGO_FCR2);
+		x &= ~0x800000;
+
+		bus_write_4(sc->sc_memr, KEYLARGO_FCR2, x);
+		/* out8(gpio + 0x10, 4); */
+
+		bus_write_1(sc->sc_memr, KEYLARGO_EXTINT_GPIO_REG_BASE + 0x0b, 0);
+		bus_write_1(sc->sc_memr, KEYLARGO_EXTINT_GPIO_REG_BASE + 0x0a, 0x28);
+		bus_write_1(sc->sc_memr, KEYLARGO_EXTINT_GPIO_REG_BASE + 0x0d, 0x28);
+		bus_write_1(sc->sc_memr, KEYLARGO_GPIO_BASE + 0x0d, 0x28);
+		bus_write_1(sc->sc_memr, KEYLARGO_GPIO_BASE + 0x0e, 0x28);
+		bus_write_4(sc->sc_memr, 0x1c000, 0);
+
+		/* Initialize the card. */
+		bus_write_4(sc->sc_memr, 0x1a3e0, 0x41);
+		x = bus_read_4(sc->sc_memr, KEYLARGO_FCR2);
+		x |= 0x800000;
+		bus_write_4(sc->sc_memr, KEYLARGO_FCR2, x);
+	} else {
+		x = bus_read_4(sc->sc_memr, KEYLARGO_FCR2);
+		x &= ~0x4;
+		bus_write_4(sc->sc_memr, KEYLARGO_FCR2, x);
+		/* out8(gpio + 0x10, 0); */
+	}
+
+	return 0;
+}
Index: sys/powerpc/powermac/uninorthpci.c
===================================================================
--- sys/powerpc/powermac/uninorthpci.c	(revision 241450)
+++ sys/powerpc/powermac/uninorthpci.c	(working copy)
@@ -86,6 +86,8 @@
 	/* Device interface */
 	DEVMETHOD(device_probe,		uninorth_probe),
 	DEVMETHOD(device_attach,	uninorth_attach),
+	DEVMETHOD(device_suspend,	bus_generic_suspend),
+	DEVMETHOD(device_resume,	bus_generic_resume),
 
 	/* pcib interface */
 	DEVMETHOD(pcib_read_config,	uninorth_read_config),
Index: sys/powerpc/powermac/maciovar.h
===================================================================
--- sys/powerpc/powermac/maciovar.h	(revision 241450)
+++ sys/powerpc/powermac/maciovar.h	(working copy)
@@ -43,10 +43,77 @@
 #define HEATHROW_FCR	0x38
 #define KEYLARGO_FCR0	0x38
 #define KEYLARGO_FCR1	0x3c
+#define KEYLARGO_FCR2	0x40
+#define KEYLARGO_FCR3	0x44
+#define KEYLARGO_FCR4	0x48
+#define KEYLARGO_FCR5	0x4c
 
 #define FCR_ENET_ENABLE	0x60000000
 #define FCR_ENET_RESET	0x80000000
 
+#define KEYLARGO_MEDIABAY	0x34
+#define KEYLARGO_MB0_DEV_ENABLE	0x00001000
+#define KEYLARGO_MB0_DEV_POWER	0x00000400
+#define KEYLARGO_MB0_DEV_RESET	0x00000200
+#define KEYLARGO_MB0_ENABLE	0x00000100
+#define KEYLARGO_MB1_DEV_ENABLE	0x10000000
+#define KEYLARGO_MB1_DEV_POWER	0x04000000
+#define KEYLARGO_MB1_DEV_RESET	0x02000000
+#define KEYLARGO_MB1_ENABLE	0x01000000
+
+#define KEYLARGO_GPIO_BASE	0x6a
+#define KEYLARGO_GPIO_LEVELS_0	0x50
+#define KEYLARGO_GPIO_LEVELS_1	0x54
+
+#define KEYLARGO_EXTINT_GPIO_REG_BASE	0x58
+
+#define FCR0_CHOOSE_SCCB	0x00000001
+#define FCR0_CHOOSE_SCCA	0x00000002
+#define FCR0_SLOW_SCC_PCLK	0x00000004
+#define FCR0_RESET_SCC		0x00000008
+#define FCR0_SCCA_ENABLE	0x00000010
+#define FCR0_SCCB_ENABLE	0x00000020
+#define FCR0_SCC_CELL_ENABLE	0x00000040
+#define FCR0_IRDA_ENABLE	0x00008000
+#define FCR0_IRDA_CLK32_ENABLE	0x00010000
+#define FCR0_IRDA_CLK19_ENABLE	0x00020000
+
+#define FCR0_USB_REF_SUSPEND	0x10000000
+
+#define FCR1_AUDIO_SEL_22MCLK	0x00000002
+#define FCR1_AUDIO_CLK_ENABLE	0x00000008
+#define FCR1_AUDIO_CLKOUT_ENABLE	0x00000020
+#define FCR1_AUDIO_CELL_ENABLE	0x00000040
+#define FCR1_I2S0_CELL_ENABLE	0x00000400
+#define FCR1_I2S0_CLK_ENABLE	0x00001000
+#define FCR1_I2S0_ENABLE	0x00002000
+#define FCR1_I2S1_CELL_ENABLE	0x00020000
+#define FCR1_I2S1_CLK_ENABLE	0x00080000
+#define FCR1_I2S1_ENABLE	0x00100000
+#define FCR1_EIDE0_ENABLE	0x00800000
+#define FCR1_EIDE0_RESET	0x01000000
+#define FCR1_EIDE1_ENABLE	0x04000000
+#define FCR1_EIDE1_RESET	0x08000000
+#define FCR1_UIDE_ENABLE	0x20000000
+#define FCR1_UIDE_RESET		0x40000000
+
+#define FCR2_IOBUS_ENABLE	0x00000002
+
+#define FCR3_SHUTDOWN_PLL_TOTAL	0x00000001
+#define FCR3_SHUTDOWN_PLL_KW6	0x00000002
+#define FCR3_SHUTDOWN_PLL_KW4	0x00000004
+#define FCR3_SHUTDOWN_PLL_KW35	0x00000008
+#define FCR3_SHUTDOWN_PLL_KW12	0x00000010
+#define FCR3_SHUTDOWN_PLL_2X	0x00000080
+#define FCR3_CLK_66_ENABLE	0x00000100
+#define FCR3_CLK_49_ENABLE	0x00000200
+#define FCR3_CLK_45_ENABLE	0x00000400
+#define FCR3_CLK_31_ENABLE	0x00000800
+#define FCR3_TMR_CLK18_ENABLE	0x00001000
+#define FCR3_I2S1_CLK18_ENABLE	0x00002000
+#define FCR3_I2S0_CLK18_ENABLE	0x00004000
+#define FCR3_VA_CLK16_ENABLE	0x00008000
+
 /*
  * Format of a macio reg property entry.
  */
@@ -66,4 +133,6 @@
 	struct resource_list mdi_resources;
 };
 
+extern int macio_enable_wireless(device_t, bool);
+
 #endif /* _MACIO_MACIOVAR_H_ */
Index: sys/powerpc/powermac/uninorthvar.h
===================================================================
--- sys/powerpc/powermac/uninorthvar.h	(revision 241450)
+++ sys/powerpc/powermac/uninorthvar.h	(working copy)
@@ -76,10 +76,30 @@
 #define UNIN_CLOCKCNTL_GMAC	0x2
 
 /*
+ * Power management register
+ */
+#define UNIN_PWR_MGMT		0x30
+#define UNIN_PWR_NORMAL		0x00
+#define UNIN_PWR_IDLE2		0x01
+#define UNIN_PWR_SLEEP		0x02
+#define UNIN_PWR_SAVE		0x03
+#define UNIN_PWR_MASK		0x03
+
+/*
+ * Hardware initialization state register
+ */
+#define UNIN_HWINIT_STATE	0x70
+#define UNIN_SLEEPING		0x01
+#define UNIN_RUNNING		0x02
+
+
+/*
  * Toggle registers
  */
 #define UNIN_TOGGLE_REG		0xe0
 #define UNIN_MPIC_RESET		0x2
 #define UNIN_MPIC_OUTPUT_ENABLE	0x4
 
+extern int unin_chip_sleep(device_t dev, int idle);
+extern int unin_chip_resume(device_t dev);
 #endif  /* _POWERPC_POWERMAC_UNINORTHVAR_H_ */
Index: sys/powerpc/include/openpicvar.h
===================================================================
--- sys/powerpc/include/openpicvar.h	(revision 241450)
+++ sys/powerpc/include/openpicvar.h	(working copy)
@@ -31,7 +31,17 @@
 #define OPENPIC_DEVSTR	"OpenPIC Interrupt Controller"
 
 #define OPENPIC_IRQMAX	256	/* h/w allows more */
+#define OPENPIC_TIMER_COUNT	4
+#define OPENPIC_IPI_COUNT	4
+#define OPENPIC_TASK_PRIORITY_COUNT	4
 
+struct openpic_timer {
+	u_int	current_count_reg;
+	u_int	base_count_reg;
+	u_int	vector_priority_reg;
+	u_int	dest_reg;
+};
+
 struct openpic_softc {
 	device_t	sc_dev;
 	struct resource	*sc_memr;
@@ -45,6 +55,15 @@
 	u_int		sc_ncpu;
 	u_int		sc_nirq;
 	int		sc_psim;
+
+	struct saved_state {
+	    u_int	spurious_vector;
+	    u_int	ipi[OPENPIC_IPI_COUNT];
+	    struct openpic_timer	timers[OPENPIC_TIMER_COUNT];
+	    u_int	task_priorities[OPENPIC_TASK_PRIORITY_COUNT];
+	    u_int	*int_src_vect_priorities;
+	    u_int	*int_src_dest;
+	} saved_state;
 };
 
 extern devclass_t openpic_devclass;
@@ -65,5 +84,6 @@
 void	openpic_ipi(device_t, u_int);
 void	openpic_mask(device_t, u_int);
 void	openpic_unmask(device_t, u_int);
+int	openpic_get_priority(device_t);
 
 #endif /* _POWERPC_OPENPICVAR_H_ */
Index: sys/powerpc/include/cpu.h
===================================================================
--- sys/powerpc/include/cpu.h	(revision 241450)
+++ sys/powerpc/include/cpu.h	(working copy)
@@ -98,4 +98,6 @@
 void	fork_trampoline(void);
 void	swi_vm(void *);
 
+void	flush_disable_caches(void);
+
 #endif	/* _MACHINE_CPU_H_ */
Index: sys/powerpc/include/spr.h
===================================================================
--- sys/powerpc/include/spr.h	(revision 241450)
+++ sys/powerpc/include/spr.h	(working copy)
@@ -518,6 +518,8 @@
 #define	  MSSCR0_EMODE		  0x00200000 /* 10: MPX bus mode (read-only) */
 #define	  MSSCR0_ABD		  0x00100000 /* 11: address bus driven (read-only) */
 #define	  MSSCR0_MBZ		  0x000fffff /* 12-31: must be zero */
+#define   MSSCR0_L2PFE		  0x00000003 /* 30-31: L2 prefetch enable */
+#define	SPR_LDSTCR		0x3f8	/* .6. Load/Store Control Register */
 #define	SPR_L2PM		0x3f8	/* .6. L2 Private Memory Control Register */
 #define	SPR_L2CR		0x3f9	/* .6. L2 Control Register */
 #define	  L2CR_L2E		  0x80000000 /* 0: L2 enable */
@@ -548,6 +550,7 @@
 #define	  L2CR_L2WT		  0x00080000 /* 12: L2 write-through. */
 #define	  L2CR_L2TS		  0x00040000 /* 13: L2 test support. */
 #define	  L2CR_L2OH		  0x00030000 /* 14-15: L2 output hold. */
+#define	  L2CR_L2DO_7450	  0x00010000 /* 15: L2 data-only (MPC745x). */
 #define	  L2CR_L2SL		  0x00008000 /* 16: L2 DLL slow. */
 #define	  L2CR_L2DF		  0x00004000 /* 17: L2 differential clock. */
 #define	  L2CR_L2BYP		  0x00002000 /* 18: L2 DLL bypass. */
Index: sys/powerpc/include/pcpu.h
===================================================================
--- sys/powerpc/include/pcpu.h	(revision 241450)
+++ sys/powerpc/include/pcpu.h	(working copy)
@@ -49,7 +49,8 @@
 	uint32_t	pc_ipimask;					\
 	register_t	pc_tempsave[CPUSAVE_LEN];			\
 	register_t	pc_disisave[CPUSAVE_LEN];			\
-	register_t	pc_dbsave[CPUSAVE_LEN];
+	register_t	pc_dbsave[CPUSAVE_LEN];				\
+	void		*pc_restore;
 
 #define PCPU_MD_AIM32_FIELDS
 

--MP_/0OtZeAhMXg1GgqTp+4I7Ns.--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20121028214917.3500f21e>