Module Name: src Committed By: phx Date: Wed Oct 20 18:52:34 UTC 2010
Modified Files: src/sys/arch/macppc/dev: obio.c src/sys/arch/powerpc/include: cpu.h src/sys/arch/powerpc/oea: cpu_subr.c Log Message: Support sysctl machdep.cpu_speed for 7447A and 7448 based Macs. On those machines the CPU's DFS (Dynamic Frequency Switching) feature is used instead of a GPIO to control the speed. Two new functions in powerpc/oea/cpu_subr.c were introduced to support reading and writing of DFS: cpu_get_dfs() and cpu_set_dfs(). Also works for multiple CPUs, but not before interrupts are enabled. To generate a diff of this commit: cvs rdiff -u -r1.29 -r1.30 src/sys/arch/macppc/dev/obio.c cvs rdiff -u -r1.70 -r1.71 src/sys/arch/powerpc/include/cpu.h cvs rdiff -u -r1.55 -r1.56 src/sys/arch/powerpc/oea/cpu_subr.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/macppc/dev/obio.c diff -u src/sys/arch/macppc/dev/obio.c:1.29 src/sys/arch/macppc/dev/obio.c:1.30 --- src/sys/arch/macppc/dev/obio.c:1.29 Sat Mar 14 15:36:09 2009 +++ src/sys/arch/macppc/dev/obio.c Wed Oct 20 18:52:33 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: obio.c,v 1.29 2009/03/14 15:36:09 dsl Exp $ */ +/* $NetBSD: obio.c,v 1.30 2010/10/20 18:52:33 phx Exp $ */ /*- * Copyright (C) 1998 Internet Research Institute, Inc. @@ -32,7 +32,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: obio.c,v 1.29 2009/03/14 15:36:09 dsl Exp $"); +__KERNEL_RCSID(0, "$NetBSD: obio.c,v 1.30 2010/10/20 18:52:33 phx Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -49,6 +49,8 @@ #include <macppc/dev/obiovar.h> +#include <powerpc/cpu.h> + #include "opt_obio.h" #ifdef OBIO_DEBUG @@ -328,9 +330,9 @@ obio_setup_gpios(struct obio_softc *sc, int node) { uint32_t reg[6]; - struct sysctlnode *sysctl_node = NULL; + struct sysctlnode *sysctl_node; char name[32]; - int gpio_base, child; + int gpio_base, child, use_dfs; if (of_compatible(sc->sc_node, keylargo) == -1) return; @@ -342,6 +344,7 @@ DPRINTF("gpio_base: %02x\n", gpio_base); /* now look for voltage and bus speed gpios */ + use_dfs = 0; for (child = OF_child(node); child; child = OF_peer(child)) { if (OF_getprop(child, "name", name, sizeof(name)) < 1) @@ -358,14 +361,21 @@ DPRINTF("found voltage_gpio at %02x\n", reg[0]); sc->sc_voltage = gpio_base + reg[0]; } + if (strcmp(name, "cpu-vcore-select") == 0) { + DPRINTF("found cpu-vcore-select at %02x\n", reg[0]); + sc->sc_voltage = gpio_base + reg[0]; + /* frequency gpio is not needed, we use cpu's DFS */ + use_dfs = 1; + } } - if ((sc->sc_voltage < 0) || (sc->sc_busspeed < 0)) + if ((sc->sc_voltage < 0) || (sc->sc_busspeed < 0 && !use_dfs)) return; printf("%s: enabling Intrepid CPU speed control\n", sc->sc_dev.dv_xname); + sysctl_node = NULL; sysctl_createv(NULL, 0, NULL, (const struct sysctlnode **)&sysctl_node, CTLFLAG_READWRITE | CTLFLAG_OWNDESC | CTLFLAG_IMMEDIATE, @@ -380,15 +390,40 @@ obio_set_cpu_speed(struct obio_softc *sc, int fast) { - if ((sc->sc_voltage < 0) || (sc->sc_busspeed < 0)) + if (sc->sc_voltage < 0) return; - if (fast) { - bus_space_write_1(sc->sc_tag, sc->sc_bh, sc->sc_voltage, 5); - bus_space_write_1(sc->sc_tag, sc->sc_bh, sc->sc_busspeed, 5); - } else { - bus_space_write_1(sc->sc_tag, sc->sc_bh, sc->sc_busspeed, 4); - bus_space_write_1(sc->sc_tag, sc->sc_bh, sc->sc_voltage, 4); + if (sc->sc_busspeed >= 0) { + /* set voltage and speed via gpio */ + if (fast) { + bus_space_write_1(sc->sc_tag, sc->sc_bh, + sc->sc_voltage, 5); + bus_space_write_1(sc->sc_tag, sc->sc_bh, + sc->sc_busspeed, 5); + } else { + bus_space_write_1(sc->sc_tag, sc->sc_bh, + sc->sc_busspeed, 4); + bus_space_write_1(sc->sc_tag, sc->sc_bh, + sc->sc_voltage, 4); + } + } + else { + /* set voltage via gpio and speed via the 7447A's DFS bit */ + if (fast) { + bus_space_write_1(sc->sc_tag, sc->sc_bh, + sc->sc_voltage, 5); + DELAY(1000); + } + + /* set DFS for all cpus */ + cpu_set_dfs(fast ? 1 : 2); + DELAY(100); + + if (!fast) { + bus_space_write_1(sc->sc_tag, sc->sc_bh, + sc->sc_voltage, 4); + DELAY(1000); + } } } @@ -396,11 +431,16 @@ obio_get_cpu_speed(struct obio_softc *sc) { - if ((sc->sc_voltage < 0) || (sc->sc_busspeed < 0)) + if (sc->sc_voltage < 0) return 0; - if (bus_space_read_1(sc->sc_tag, sc->sc_bh, sc->sc_busspeed) & 1) + if (sc->sc_busspeed >= 0) { + if (bus_space_read_1(sc->sc_tag, sc->sc_bh, sc->sc_busspeed) + & 1) return 1; + } + else + return cpu_get_dfs() == 1; return 0; } @@ -421,7 +461,7 @@ node.sysctl_data = &speed; if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) { int new_reg; - + new_reg = (max(0, min(1, node.sysctl_idata))); obio_set_cpu_speed(sc, new_reg); return 0; @@ -434,4 +474,3 @@ } #endif /* OBIO_SPEEDCONTROL */ - Index: src/sys/arch/powerpc/include/cpu.h diff -u src/sys/arch/powerpc/include/cpu.h:1.70 src/sys/arch/powerpc/include/cpu.h:1.71 --- src/sys/arch/powerpc/include/cpu.h:1.70 Sat Apr 24 09:39:57 2010 +++ src/sys/arch/powerpc/include/cpu.h Wed Oct 20 18:52:33 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: cpu.h,v 1.70 2010/04/24 09:39:57 kiyohara Exp $ */ +/* $NetBSD: cpu.h,v 1.71 2010/10/20 18:52:33 phx Exp $ */ /* * Copyright (C) 1999 Wolfgang Solfrank. @@ -353,6 +353,8 @@ struct cpu_info *cpu_attach_common(struct device *, int); void cpu_setup(struct device *, struct cpu_info *); void cpu_identify(char *, size_t); +int cpu_get_dfs(void); +void cpu_set_dfs(int); void delay (unsigned int); void cpu_probe_cache(void); void dcache_flush_page(vaddr_t); Index: src/sys/arch/powerpc/oea/cpu_subr.c diff -u src/sys/arch/powerpc/oea/cpu_subr.c:1.55 src/sys/arch/powerpc/oea/cpu_subr.c:1.56 --- src/sys/arch/powerpc/oea/cpu_subr.c:1.55 Thu Feb 25 23:31:47 2010 +++ src/sys/arch/powerpc/oea/cpu_subr.c Wed Oct 20 18:52:33 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: cpu_subr.c,v 1.55 2010/02/25 23:31:47 matt Exp $ */ +/* $NetBSD: cpu_subr.c,v 1.56 2010/10/20 18:52:33 phx Exp $ */ /*- * Copyright (c) 2001 Matt Thomas. @@ -34,7 +34,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: cpu_subr.c,v 1.55 2010/02/25 23:31:47 matt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: cpu_subr.c,v 1.56 2010/10/20 18:52:33 phx Exp $"); #include "opt_ppcparam.h" #include "opt_multiprocessor.h" @@ -47,6 +47,7 @@ #include <sys/types.h> #include <sys/lwp.h> #include <sys/malloc.h> +#include <sys/xcall.h> #include <uvm/uvm_extern.h> @@ -64,6 +65,7 @@ static void cpu_config_l3cr(int); static void cpu_probe_speed(struct cpu_info *); static void cpu_idlespin(void); +static void cpu_set_dfs_xcall(void *, void *); #if NSYSMON_ENVSYS > 0 static void cpu_tau_setup(struct cpu_info *); static void cpu_tau_refresh(struct sysmon_envsys *, envsys_data_t *); @@ -984,7 +986,95 @@ mtspr(SPR_MMCR0, MMCR0_FC); - ci->ci_khz = cps / 1000; + ci->ci_khz = (cps * cpu_get_dfs()) / 1000; +} + +/* + * Read the Dynamic Frequency Switching state and return a divisor for + * the maximum frequency. + */ +int +cpu_get_dfs(void) +{ + u_int hid1, pvr, vers; + + pvr = mfpvr(); + vers = pvr >> 16; + hid1 = mfspr(SPR_HID1); + + switch (vers) { + case MPC7448: + if (hid1 & HID1_DFS4) + return 4; + case MPC7447A: + if (hid1 & HID1_DFS2) + return 2; + } + return 1; +} + +/* + * Set the Dynamic Frequency Switching divisor the same for all cpus. + */ +void +cpu_set_dfs(int div) +{ + uint64_t where; + u_int dfs_mask, pvr, vers; + + pvr = mfpvr(); + vers = pvr >> 16; + dfs_mask = 0; + + switch (vers) { + case MPC7448: + dfs_mask |= HID1_DFS4; + case MPC7447A: + dfs_mask |= HID1_DFS2; + break; + default: + printf("cpu_set_dfs: DFS not supported\n"); + return; + + } + + where = xc_broadcast(0, (xcfunc_t)cpu_set_dfs_xcall, &div, &dfs_mask); + xc_wait(where); +} + +static void +cpu_set_dfs_xcall(void *arg1, void *arg2) +{ + u_int dfs_mask, hid1, old_hid1; + int *divisor, s; + + divisor = arg1; + dfs_mask = *(u_int *)arg2; + + s = splhigh(); + hid1 = old_hid1 = mfspr(SPR_HID1); + + switch (*divisor) { + case 1: + hid1 &= ~dfs_mask; + break; + case 2: + hid1 &= ~(dfs_mask & HID1_DFS4); + hid1 |= dfs_mask & HID1_DFS2; + break; + case 4: + hid1 &= ~(dfs_mask & HID1_DFS2); + hid1 |= dfs_mask & HID1_DFS4; + break; + } + + if (hid1 != old_hid1) { + __asm volatile("sync"); + mtspr(SPR_HID1, hid1); + __asm volatile("sync;isync"); + } + + splx(s); } #if NSYSMON_ENVSYS > 0