Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch Support sysctl machdep.cpu_speed for 7447A and 7448...
details: https://anonhg.NetBSD.org/src/rev/9f7e5cf5edbf
branches: trunk
changeset: 758132:9f7e5cf5edbf
user: phx <phx%NetBSD.org@localhost>
date: Wed Oct 20 18:52:33 2010 +0000
description:
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.
diffstat:
sys/arch/macppc/dev/obio.c | 71 +++++++++++++++++++++++------
sys/arch/powerpc/include/cpu.h | 4 +-
sys/arch/powerpc/oea/cpu_subr.c | 96 +++++++++++++++++++++++++++++++++++++++-
3 files changed, 151 insertions(+), 20 deletions(-)
diffs (300 lines):
diff -r 6f2b8e4ddeaa -r 9f7e5cf5edbf sys/arch/macppc/dev/obio.c
--- a/sys/arch/macppc/dev/obio.c Wed Oct 20 18:50:46 2010 +0000
+++ b/sys/arch/macppc/dev/obio.c Wed Oct 20 18:52:33 2010 +0000
@@ -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 */
-
diff -r 6f2b8e4ddeaa -r 9f7e5cf5edbf sys/arch/powerpc/include/cpu.h
--- a/sys/arch/powerpc/include/cpu.h Wed Oct 20 18:50:46 2010 +0000
+++ b/sys/arch/powerpc/include/cpu.h Wed Oct 20 18:52:33 2010 +0000
@@ -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);
diff -r 6f2b8e4ddeaa -r 9f7e5cf5edbf sys/arch/powerpc/oea/cpu_subr.c
--- a/sys/arch/powerpc/oea/cpu_subr.c Wed Oct 20 18:50:46 2010 +0000
+++ b/sys/arch/powerpc/oea/cpu_subr.c Wed Oct 20 18:52:33 2010 +0000
@@ -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
Home |
Main Index |
Thread Index |
Old Index