Port-powerpc 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