From owner-svn-src-all@FreeBSD.ORG Wed Jan 15 06:17:18 2014 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id B286D806; Wed, 15 Jan 2014 06:17:18 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 9C5641D17; Wed, 15 Jan 2014 06:17:18 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.7/8.14.7) with ESMTP id s0F6HIjW081141; Wed, 15 Jan 2014 06:17:18 GMT (envelope-from jhibbits@svn.freebsd.org) Received: (from jhibbits@localhost) by svn.freebsd.org (8.14.7/8.14.7/Submit) id s0F6HFsI081122; Wed, 15 Jan 2014 06:17:15 GMT (envelope-from jhibbits@svn.freebsd.org) Message-Id: <201401150617.s0F6HFsI081122@svn.freebsd.org> From: Justin Hibbits Date: Wed, 15 Jan 2014 06:17:15 +0000 (UTC) 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 X-SVN-Group: stable-10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.17 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 15 Jan 2014 06:17:18 -0000 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 #include #include +#include #include #include @@ -43,11 +44,18 @@ __FBSDID("$FreeBSD$"); #include #include +#include +#include /* For save_vec() */ #include +#include +#include /* For save_fpu() */ +#include #include #include +#include #include #include +#include #include #include @@ -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, ®, 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 +#include #include 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 #include #include +#include #include #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) ;