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