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, ®, 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, ®, 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, ®, 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>