Port-macppc archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

7447A DFS support for PowerBook G4



Hi,

here is a small patch for macppc/dev/obio.c, which enables cpu speed control
for 7447A PowerBooks. In contrast to other Intrepid-based PowerBooks, which
can change the cpu speed with two GPIO registers (frequency-gpio and
voltage-gpio), this one uses the DFS2 bit of the 7447A's HID1 register to
halve the frequency.

This is a special feature of the 7447A called Dynamic Frequency Switching.
The 7448 even has an additional DFS4 bit to divide the frequency by 4 (are
there any popular systems equipped with 7448?).

For the user it is completely transparent. There is no difference to other
PowerBooks. Just compile a kernel with option OBIO_SPEED_CONTROL and use
the machdep.cpu_speed sysctl to configure the cpu into half or full speed.

Problems to be resolved until I commit the patch:

1. What I don't like is reading/writing to HID1 within obio.c. This should
probably go into powerpc/oea/cpu_subr.c? I'm open to any suggestion about a
cleaner implementation.

2. What about multiple cpus? Do systems with two 7447A exist? The DFS2 bit
would have to be set for both. I don't know how do to it yet.

3. The PowerBook starts with DFS2 set (i.e. half speed). So the cpu-speed is
calculated wrong. Should that be fixed somehow? For example by taking the
status of DFS2 into account and double the measured frequency when set?


Index: obio.c
===================================================================
RCS file: /cvsroot/src/sys/arch/macppc/dev/obio.c,v
retrieving revision 1.29
diff -u -r1.29 obio.c
--- obio.c  14 Mar 2009 15:36:09 -0000  1.29
+++ obio.c  9 Oct 2010 18:07:06 -0000
@@ -49,6 +49,10 @@
 
 #include <macppc/dev/obiovar.h>
 
+#include <powerpc/spr.h>
+#include <powerpc/oea/hid.h>
+#include <powerpc/oea/spr.h>
+
 #include "opt_obio.h"
 
 #ifdef OBIO_DEBUG
@@ -328,9 +332,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 +346,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 +363,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,
@@ -379,16 +391,46 @@
 static void
 obio_set_cpu_speed(struct obio_softc *sc, int fast)
 {
+   u_int hid1;
 
-   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);
+       }
+       hid1 = mfspr(SPR_HID1);
+       if (fast)
+           hid1 &= ~HID1_DFS2;
+       else
+           hid1 |= HID1_DFS2;
+       __asm volatile("sync");
+       mtspr(SPR_HID1, hid1);
+       __asm volatile("sync;isync");
+       DELAY(100);
+       if (!fast) {
+           bus_space_write_1(sc->sc_tag, sc->sc_bh,
+               sc->sc_voltage, 4);
+           DELAY(1000);
+       }
    }
 }
 
@@ -396,11 +438,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 (mfspr(SPR_HID1) & HID1_DFS2) == 0;
 
    return 0;
 }


-- 
Frank Wille



Home | Main Index | Thread Index | Old Index