Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 15 Jan 2014 06:17:15 +0000 (UTC)
From:      Justin Hibbits <jhibbits@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org
Subject:   svn commit: r260674 - in stable/10/sys: conf powerpc/aim powerpc/cpufreq powerpc/include powerpc/powermac powerpc/powerpc
Message-ID:  <201401150617.s0F6HFsI081122@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jhibbits
Date: Wed Jan 15 06:17:15 2014
New Revision: 260674
URL: http://svnweb.freebsd.org/changeset/base/260674

Log:
  MFC r259284,r259287
  
  Add PMU-based CPU frequency scalling.  This is used on most Titanium
  PowerBooks.

Added:
  stable/10/sys/powerpc/cpufreq/pmufreq.c
     - copied, changed from r259284, head/sys/powerpc/cpufreq/pmufreq.c
Modified:
  stable/10/sys/conf/files.powerpc
  stable/10/sys/powerpc/aim/mp_cpudep.c
  stable/10/sys/powerpc/include/cpu.h
  stable/10/sys/powerpc/include/dbdma.h
  stable/10/sys/powerpc/include/pcpu.h
  stable/10/sys/powerpc/include/spr.h
  stable/10/sys/powerpc/powermac/platform_powermac.c
  stable/10/sys/powerpc/powermac/pmu.c
  stable/10/sys/powerpc/powermac/pmuvar.h
  stable/10/sys/powerpc/powermac/uninorth.c
  stable/10/sys/powerpc/powermac/uninorthvar.h
  stable/10/sys/powerpc/powermac/viareg.h
  stable/10/sys/powerpc/powerpc/mp_machdep.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/conf/files.powerpc
==============================================================================
--- stable/10/sys/conf/files.powerpc	Wed Jan 15 05:52:06 2014	(r260673)
+++ stable/10/sys/conf/files.powerpc	Wed Jan 15 06:17:15 2014	(r260674)
@@ -116,6 +116,7 @@ powerpc/booke/trap.c		optional	booke
 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 pmu
 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

Modified: stable/10/sys/powerpc/aim/mp_cpudep.c
==============================================================================
--- stable/10/sys/powerpc/aim/mp_cpudep.c	Wed Jan 15 05:52:06 2014	(r260673)
+++ stable/10/sys/powerpc/aim/mp_cpudep.c	Wed Jan 15 06:17:15 2014	(r260674)
@@ -322,17 +322,13 @@ cpudep_ap_setup()
 		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,17 @@ cpudep_ap_setup()
 		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;
+		}
+		
 		reg = mpc74xx_l2_enable(bsp_state[2]);
 		reg = mpc74xx_l1d_enable();
 		reg = mpc74xx_l1i_enable();

Copied and modified: stable/10/sys/powerpc/cpufreq/pmufreq.c (from r259284, head/sys/powerpc/cpufreq/pmufreq.c)
==============================================================================
--- head/sys/powerpc/cpufreq/pmufreq.c	Fri Dec 13 02:37:35 2013	(r259284, copy source)
+++ stable/10/sys/powerpc/cpufreq/pmufreq.c	Wed Jan 15 06:17:15 2014	(r260674)
@@ -106,9 +106,9 @@ pmufreq_identify(driver_t *driver, devic
 static int
 pmufreq_probe(device_t dev)
 {
-	uint32_t min_freq;
 	struct pmufreq_softc *sc;
 	phandle_t node;
+	uint32_t min_freq;
 
 	if (resource_disabled("pmufreq", 0))
 		return (ENXIO);
@@ -174,8 +174,7 @@ static int
 pmufreq_set(device_t dev, const struct cf_setting *set)
 {
 	struct pmufreq_softc *sc;
-	int speed_sel;
-	int error;
+	int error, speed_sel;
 
 	if (set == NULL)
 		return (EINVAL);
@@ -191,7 +190,7 @@ pmufreq_set(device_t dev, const struct c
 	if (error == 0)
 		sc->curfreq = set->freq;
 
-	return error;
+	return (error);
 }
 
 static int

Modified: stable/10/sys/powerpc/include/cpu.h
==============================================================================
--- stable/10/sys/powerpc/include/cpu.h	Wed Jan 15 05:52:06 2014	(r260673)
+++ stable/10/sys/powerpc/include/cpu.h	Wed Jan 15 06:17:15 2014	(r260674)
@@ -98,4 +98,6 @@ void	cpu_reset(void);
 void	fork_trampoline(void);
 void	swi_vm(void *);
 
+void	flush_disable_caches(void);
+
 #endif	/* _MACHINE_CPU_H_ */

Modified: stable/10/sys/powerpc/include/dbdma.h
==============================================================================
--- stable/10/sys/powerpc/include/dbdma.h	Wed Jan 15 05:52:06 2014	(r260673)
+++ stable/10/sys/powerpc/include/dbdma.h	Wed Jan 15 06:17:15 2014	(r260674)
@@ -147,4 +147,7 @@ void dbdma_insert_branch(dbdma_channel_t
 
 void dbdma_sync_commands(dbdma_channel_t *chan, bus_dmasync_op_t op);
 
+void dbdma_save_state(dbdma_channel_t *chan);
+void dbdma_restore_state(dbdma_channel_t *chan);
+
 #endif /* _MACHINE_DBDMA_H_ */

Modified: stable/10/sys/powerpc/include/pcpu.h
==============================================================================
--- stable/10/sys/powerpc/include/pcpu.h	Wed Jan 15 05:52:06 2014	(r260673)
+++ stable/10/sys/powerpc/include/pcpu.h	Wed Jan 15 06:17:15 2014	(r260674)
@@ -49,7 +49,8 @@ struct pmap;
 	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						\
 	/* char		__pad[0] */

Modified: stable/10/sys/powerpc/include/spr.h
==============================================================================
--- stable/10/sys/powerpc/include/spr.h	Wed Jan 15 05:52:06 2014	(r260673)
+++ stable/10/sys/powerpc/include/spr.h	Wed Jan 15 06:17:15 2014	(r260674)
@@ -519,6 +519,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 */
@@ -543,12 +545,14 @@
 				      Setting this bit disables instruction
 				      caching. */
 #define	  L2CR_L2I		  0x00200000 /* 10: L2 global invalidate. */
+#define	  L2CR_L2IO_7450	  0x00010000 /* 11: L2 instruction-only (MPC745x). */
 #define	  L2CR_L2CTL		  0x00100000 /* 11: L2 RAM control (ZZ enable).
 				      Enables automatic operation of the
 				      L2ZZ (low-power mode) signal. */
 #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. */

Modified: stable/10/sys/powerpc/powermac/platform_powermac.c
==============================================================================
--- stable/10/sys/powerpc/powermac/platform_powermac.c	Wed Jan 15 05:52:06 2014	(r260673)
+++ stable/10/sys/powerpc/powermac/platform_powermac.c	Wed Jan 15 06:17:15 2014	(r260674)
@@ -326,6 +326,110 @@ powermac_smp_start_cpu(platform_t plat, 
 #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 *memp;
+	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);
+
+	/*
+	 * Perform this in two stages: Flush the cache starting in RAM, then do it
+	 * from ROM.
+	 */
+	memp = (volatile uint32_t *)0x00000000;
+	for (i = 0; i < 128 * 1024; i++) {
+		temp = *memp;
+		__asm__ __volatile__("dcbf 0,%0" :: "r"(memp));
+		memp += 32/sizeof(*memp);
+	}
+
+	memp = (volatile uint32_t *)0xfff00000;
+	x = 0xfe;
+
+	for (; x != 0xff;) {
+		mtspr(SPR_LDSTCR, x);
+		for (i = 0; i < 128; i++) {
+			temp = *memp;
+			__asm__ __volatile__("dcbf 0,%0" :: "r"(memp));
+			memp += 32/sizeof(*memp);
+		}
+		x = ((x << 1) | 1) & 0xff;
+	}
+	mtspr(SPR_LDSTCR, 0);
+
+	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 | L3CR_L3DO);
+		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)
 {

Modified: stable/10/sys/powerpc/powermac/pmu.c
==============================================================================
--- stable/10/sys/powerpc/powermac/pmu.c	Wed Jan 15 05:52:06 2014	(r260673)
+++ stable/10/sys/powerpc/powermac/pmu.c	Wed Jan 15 06:17:15 2014	(r260674)
@@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/conf.h>
 #include <sys/kernel.h>
 #include <sys/clock.h>
+#include <sys/proc.h>
 #include <sys/reboot.h>
 #include <sys/sysctl.h>
 
@@ -43,11 +44,18 @@ __FBSDID("$FreeBSD$");
 #include <dev/ofw/openfirm.h>
 #include <dev/led/led.h>
 
+#include <machine/_inttypes.h>
+#include <machine/altivec.h>	/* For save_vec() */
 #include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/fpu.h>	/* For save_fpu() */
+#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>
@@ -59,6 +67,11 @@ __FBSDID("$FreeBSD$");
 #include "clock_if.h"
 #include "pmuvar.h"
 #include "viareg.h"
+#include "uninorthvar.h"	/* For unin_chip_sleep()/unin_chip_wake() */
+
+#define PMU_DEFAULTS	PMU_INT_TICK | PMU_INT_ADB | \
+	PMU_INT_PCEJECT | PMU_INT_SNDBRT | \
+	PMU_INT_BATTERY | PMU_INT_ENVIRONMENT
 
 /*
  * Bus interface
@@ -93,6 +106,7 @@ static int	pmu_acline_state(SYSCTL_HANDL
 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_sleep_int(void);
 
 /*
  * List of battery-related sysctls we might ask for
@@ -115,8 +129,6 @@ static device_method_t  pmu_methods[] = 
 	DEVMETHOD(device_attach,	pmu_attach),
         DEVMETHOD(device_detach,        pmu_detach),
         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
-        DEVMETHOD(device_suspend,       bus_generic_suspend),
-        DEVMETHOD(device_resume,        bus_generic_resume),
 
 	/* ADB bus interface */
 	DEVMETHOD(adb_hb_send_raw_packet,   pmu_adb_send),
@@ -193,7 +205,7 @@ static signed char pm_send_cmd_type[] = 
 	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 +241,7 @@ static signed char pm_receive_cmd_type[]
 	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 +369,13 @@ pmu_attach(device_t dev)
 
 	/* 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);
@@ -1018,3 +1031,95 @@ pmu_settime(device_t dev, struct timespe
 	return (0);
 }
 
+static register_t sprgs[4];
+static register_t srrs[2];
+extern void *ap_pcpu;
+
+void pmu_sleep_int(void)
+{
+	static u_quad_t timebase = 0;
+	jmp_buf resetjb;
+	struct thread *fputd;
+	struct thread *vectd;
+	register_t hid0;
+	register_t msr;
+	register_t saved_msr;
+
+	ap_pcpu = pcpup;
+
+	PCPU_SET(restore, &resetjb);
+
+	*(unsigned long *)0x80 = 0x100;
+	saved_msr = mfmsr();
+	fputd = PCPU_GET(fputhread);
+	vectd = PCPU_GET(vecthread);
+	if (fputd != NULL)
+		save_fpu(fputd);
+	if (vectd != NULL)
+		save_vec(vectd);
+	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);
+		timebase = mftb();
+		powerpc_sync();
+		flush_disable_caches();
+		hid0 = mfspr(SPR_HID0);
+		hid0 = (hid0 & ~(HID0_DOZE | HID0_NAP)) | HID0_SLEEP;
+		powerpc_sync();
+		isync();
+		msr = mfmsr() | PSL_POW;
+		mtspr(SPR_HID0, hid0);
+		powerpc_sync();
+
+		while (1)
+			mtmsr(msr);
+	}
+	mttb(timebase);
+	PCPU_SET(curthread, curthread);
+	PCPU_SET(curpcb, curthread->td_pcb);
+	pmap_activate(curthread);
+	powerpc_sync();
+	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);
+	if (fputd == curthread)
+		enable_fpu(curthread);
+	if (vectd == curthread)
+		enable_vec(curthread);
+	powerpc_sync();
+}
+
+int
+pmu_set_speed(int low_speed)
+{
+	struct pmu_softc *sc;
+	uint8_t sleepcmd[] = {'W', 'O', 'O', 'F', 0};
+	uint8_t resp[16];
+
+	sc = device_get_softc(pmu);
+	pmu_write_reg(sc, vIER, 0x10);
+	spinlock_enter();
+	mtdec(0x7fffffff);
+	mb();
+	mtdec(0x7fffffff);
+
+	sleepcmd[4] = low_speed;
+	pmu_send(sc, PMU_CPU_SPEED, 5, sleepcmd, 16, resp);
+	unin_chip_sleep(NULL, 1);
+	pmu_sleep_int();
+	unin_chip_wake(NULL);
+
+	mtdec(1);	/* Force a decrementer exception */
+	spinlock_exit();
+	pmu_write_reg(sc, vIER, 0x90);
+
+	return (0);
+}

Modified: stable/10/sys/powerpc/powermac/pmuvar.h
==============================================================================
--- stable/10/sys/powerpc/powermac/pmuvar.h	Wed Jan 15 05:52:06 2014	(r260673)
+++ stable/10/sys/powerpc/powermac/pmuvar.h	Wed Jan 15 06:17:15 2014	(r260674)
@@ -160,7 +160,8 @@ struct pmu_softc {
 	volatile int	sc_autopoll;
 	int		sc_batteries;
 	struct cdev	*sc_leddev;
-	int	lid_closed;
+	int		lid_closed;
+	uint8_t		saved_regs[9];
 };
 
 struct pmu_battstate {
@@ -172,4 +173,6 @@ struct pmu_battstate {
 	int voltage;
 };
 
+int pmu_set_speed(int low_speed);
+
 #endif /* PMUVAR_H */

Modified: stable/10/sys/powerpc/powermac/uninorth.c
==============================================================================
--- stable/10/sys/powerpc/powermac/uninorth.c	Wed Jan 15 05:52:06 2014	(r260673)
+++ stable/10/sys/powerpc/powermac/uninorth.c	Wed Jan 15 06:17:15 2014	(r260674)
@@ -136,6 +136,13 @@ static driver_t	unin_chip_driver = {
 
 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 +217,30 @@ unin_chip_add_reg(phandle_t devnode, str
 }
 
 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_mpic(device_t dev)
+unin_enable_gmac(device_t dev)
 {
-	volatile u_int *toggle;
-	struct unin_chip_softc *sc;
-	u_int32_t tmpl;
+	unin_update_reg(dev, UNIN_CLOCKCNTL, UNIN_CLOCKCNTL_GMAC, 0);
+}
 
-	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);
+static void
+unin_enable_mpic(device_t dev)
+{
+	unin_update_reg(dev, UNIN_TOGGLE_REG, UNIN_MPIC_RESET | UNIN_MPIC_OUTPUT_ENABLE, 0);
 }
 
 static int
@@ -301,6 +307,9 @@ unin_chip_attach(device_t dev)
 		return (error);
 	}
 
+	if (unin_chip == NULL)
+		unin_chip = dev;
+
         /*
 	 * Iterate through the sub-devices
 	 */
@@ -621,3 +630,33 @@ unin_chip_get_devinfo(device_t dev, devi
 	return (&dinfo->udi_obdinfo);
 }
 
+int
+unin_chip_wake(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);
+
+	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);
+}

Modified: stable/10/sys/powerpc/powermac/uninorthvar.h
==============================================================================
--- stable/10/sys/powerpc/powermac/uninorthvar.h	Wed Jan 15 05:52:06 2014	(r260673)
+++ stable/10/sys/powerpc/powermac/uninorthvar.h	Wed Jan 15 06:17:15 2014	(r260674)
@@ -28,6 +28,8 @@
 #ifndef	_POWERPC_POWERMAC_UNINORTHVAR_H_
 #define	_POWERPC_POWERMAC_UNINORTHVAR_H_
 
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/ofw/ofw_pci.h>
 #include <powerpc/ofw/ofw_pci.h>
 
 struct uninorth_softc {
@@ -76,10 +78,30 @@ struct unin_chip_devinfo {
 #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_wake(device_t dev);
 #endif  /* _POWERPC_POWERMAC_UNINORTHVAR_H_ */

Modified: stable/10/sys/powerpc/powermac/viareg.h
==============================================================================
--- stable/10/sys/powerpc/powermac/viareg.h	Wed Jan 15 05:52:06 2014	(r260673)
+++ stable/10/sys/powerpc/powermac/viareg.h	Wed Jan 15 06:17:15 2014	(r260674)
@@ -30,14 +30,16 @@
 
 /* VIA interface registers */
 #define vBufB		0x0000	/* register B */
-#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 */
 #define vIFR		0x1a00	/* interrupt flag register */
 #define vIER		0x1c00	/* interrupt enable register */
+#define vBufA		0x1e00	/* register A */
 
 #define vPB		0x0000
 #define vPB3		0x08

Modified: stable/10/sys/powerpc/powerpc/mp_machdep.c
==============================================================================
--- stable/10/sys/powerpc/powerpc/mp_machdep.c	Wed Jan 15 05:52:06 2014	(r260673)
+++ stable/10/sys/powerpc/powerpc/mp_machdep.c	Wed Jan 15 06:17:15 2014	(r260674)
@@ -54,6 +54,7 @@ __FBSDID("$FreeBSD$");
 #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"
@@ -66,10 +67,21 @@ volatile static 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;
+
+	/* The following is needed for restoring from sleep. */
+#ifdef __powerpc64__
+	/* Writing to the time base register is hypervisor-privileged */
+	if (mfmsr() & PSL_HV)
+		mttb(0);
+#else
+	mttb(0);
+#endif
 	/* Set up important bits on the CPU (HID registers, etc.) */
 	cpudep_ap_setup();
 
@@ -78,6 +90,11 @@ machdep_ap_bootstrap(void)
 	PCPU_SET(awake, 1);
 	__asm __volatile("msync; isync");
 
+	restore = PCPU_GET(restore);
+	if (restore != NULL) {
+		longjmp(*restore, 1);
+	}
+
 	while (ap_letgo == 0)
 		;
 



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