summaryrefslogtreecommitdiff
path: root/sys/arch
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2005-11-26 22:40:32 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2005-11-26 22:40:32 +0000
commit1e4337b42cc5692af628f6d84540e3ac421da618 (patch)
treefe9f2beec2c58b09274fdb827edcd314b434b3d4 /sys/arch
parent4d01ec47c26f496d60f3d7bb184643ea32e807d8 (diff)
Frequency scaling for IBM 970FX.
ok drahn@
Diffstat (limited to 'sys/arch')
-rw-r--r--sys/arch/macppc/macppc/cpu.c87
-rw-r--r--sys/arch/powerpc/include/cpu.h4
-rw-r--r--sys/arch/powerpc/powerpc/cpu_subr.c22
3 files changed, 103 insertions, 10 deletions
diff --git a/sys/arch/macppc/macppc/cpu.c b/sys/arch/macppc/macppc/cpu.c
index 0d6117912c9..1a0a7143db2 100644
--- a/sys/arch/macppc/macppc/cpu.c
+++ b/sys/arch/macppc/macppc/cpu.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.c,v 1.33 2005/11/13 21:46:03 drahn Exp $ */
+/* $OpenBSD: cpu.c,v 1.34 2005/11/26 22:40:31 kettenis Exp $ */
/*
* Copyright (c) 1997 Per Fogelstrom
@@ -55,7 +55,7 @@
#define HID0_BHT (1 << (31-29))
/* SCOM addresses (24-bit) */
-#define SCOM_PCR 0x400801 /* Power Management Control Register */
+#define SCOM_PCR 0x0aa001 /* Power Control Register */
#define SCOM_PSR 0x408001 /* Power Tuning Status Register */
/* SCOMC format */
@@ -64,8 +64,10 @@
#define SCOMC_READ 0x00008000
/* Power (Tuning) Status Register */
-#define PSR_FREQ_MASK 0x0300000000000000LL
-#define PSR_FREQ_HALF 0x0100000000000000LL
+#define PSR_CMD_RECEIVED 0x2000000000000000LL
+#define PSR_CMD_COMPLETED 0x1000000000000000LL
+#define PSR_FREQ_MASK 0x0300000000000000LL
+#define PSR_FREQ_HALF 0x0100000000000000LL
char cpu_model[80];
char machine[] = MACHINE; /* cpu architecture */
@@ -82,7 +84,10 @@ struct cfdriver cpu_cd = {
NULL, "cpu", DV_DULL
};
-void config_l2cr(int cpu);
+void ppc64_scale_frequency(u_int);
+int ppc64_setperf(int);
+
+void config_l2cr(int);
int
cpumatch(parent, cfdata, aux)
@@ -112,6 +117,66 @@ ppc_cpuspeed(int *freq)
return (0);
}
+static u_int32_t ppc_power_mode_data[2];
+
+void
+ppc64_scale_frequency(u_int freq_scale)
+{
+ u_int64_t psr;
+ int s;
+
+ s = ppc_intr_disable();
+
+ /* Clear PCRH and PCR. */
+ ppc_mtscomd(0x00000000);
+ ppc_mtscomc(SCOM_PCR << SCOMC_ADDR_SHIFT);
+ ppc_mtscomd(0x80000000);
+ ppc_mtscomc(SCOM_PCR << SCOMC_ADDR_SHIFT);
+
+ /* Set PCR. */
+ ppc_mtscomd(ppc_power_mode_data[freq_scale] | 0x80000000);
+ ppc_mtscomc(SCOM_PCR << SCOMC_ADDR_SHIFT);
+
+ /* Wait until frequency change is completed. */
+ do {
+ ppc64_mtscomc((SCOM_PSR << SCOMC_ADDR_SHIFT) | SCOMC_READ);
+ psr = ppc64_mfscomd();
+ ppc64_mfscomc();
+ if (psr & PSR_CMD_COMPLETED)
+ break;
+ DELAY(100);
+ } while (psr & PSR_CMD_RECEIVED);
+
+ if ((psr & PSR_FREQ_MASK) == PSR_FREQ_HALF)
+ ppc_curfreq = ppc_maxfreq / 2;
+ else
+ ppc_curfreq = ppc_maxfreq;
+
+ ppc_intr_enable(s);
+}
+
+extern int perflevel;
+
+int
+ppc64_setperf(int speed)
+{
+ if (speed <= 50) {
+ if (ppc_curfreq == ppc_maxfreq / 2)
+ return (0);
+
+ ppc64_scale_frequency(1);
+ perflevel = 50;
+ } else {
+ if (ppc_curfreq == ppc_maxfreq)
+ return (0);
+
+ ppc64_scale_frequency(0);
+ perflevel = 100;
+ }
+
+ return (0);
+}
+
int ppc_proc_is_64b;
extern u_int32_t rfi_inst, rfid_inst, nop_inst;
struct patch {
@@ -165,7 +230,7 @@ cpuattach(struct device *parent, struct device *dev, void *aux)
u_int32_t cpu, pvr, hid0;
char name[32];
int qhandle, phandle;
- unsigned int clock_freq = 0;
+ u_int32_t clock_freq = 0;
pvr = ppc_mfpvr();
cpu = pvr >> 16;
@@ -236,7 +301,7 @@ cpuattach(struct device *parent, struct device *dev, void *aux)
if (OF_getprop(qhandle, "device_type", name, sizeof name) >= 0
&& !strcmp(name, "cpu")
&& OF_getprop(qhandle, "clock-frequency",
- &clock_freq , sizeof clock_freq ) >= 0)
+ &clock_freq, sizeof clock_freq) >= 0)
{
break;
}
@@ -267,8 +332,14 @@ cpuattach(struct device *parent, struct device *dev, void *aux)
ppc64_mfscomc();
ppc_intr_enable(s);
- if ((psr & PSR_FREQ_MASK) == PSR_FREQ_HALF)
+ if ((psr & PSR_FREQ_MASK) == PSR_FREQ_HALF) {
ppc_curfreq = ppc_maxfreq / 2;
+ perflevel = 50;
+ }
+
+ if (OF_getprop(qhandle, "power-mode-data",
+ &ppc_power_mode_data, sizeof ppc_power_mode_data) >= 8)
+ cpu_setperf = ppc64_setperf;
}
/* power savings mode */
diff --git a/sys/arch/powerpc/include/cpu.h b/sys/arch/powerpc/include/cpu.h
index d9a23242a13..b36babb439c 100644
--- a/sys/arch/powerpc/include/cpu.h
+++ b/sys/arch/powerpc/include/cpu.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.h,v 1.25 2005/11/13 21:46:03 drahn Exp $ */
+/* $OpenBSD: cpu.h,v 1.26 2005/11/26 22:40:30 kettenis Exp $ */
/* $NetBSD: cpu.h,v 1.1 1996/09/30 16:34:21 ws Exp $ */
/*
@@ -196,8 +196,10 @@ ppc_mtsrin(u_int32_t val, u_int32_t sn_shifted)
}
u_int64_t ppc64_mfscomc(void);
+void ppc_mtscomc(u_int32_t);
void ppc64_mtscomc(u_int64_t);
u_int64_t ppc64_mfscomd(void);
+void ppc_mtscomd(u_int32_t);
/*
* General functions to enable and disable interrupts
diff --git a/sys/arch/powerpc/powerpc/cpu_subr.c b/sys/arch/powerpc/powerpc/cpu_subr.c
index e81beda6aa6..98d1c0478e9 100644
--- a/sys/arch/powerpc/powerpc/cpu_subr.c
+++ b/sys/arch/powerpc/powerpc/cpu_subr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu_subr.c,v 1.1 2005/11/08 20:30:47 kettenis Exp $ */
+/* $OpenBSD: cpu_subr.c,v 1.2 2005/11/26 22:40:31 kettenis Exp $ */
/*
* Copyright (c) 2005 Mark Kettenis
@@ -20,6 +20,26 @@
#include <machine/cpu.h>
+void
+ppc_mtscomc(u_int32_t val)
+{
+ int s;
+
+ s = ppc_intr_disable();
+ __asm __volatile ("mtspr 276,%0; isync" :: "r" (val));
+ ppc_intr_enable(s);
+}
+
+void
+ppc_mtscomd(u_int32_t val)
+{
+ int s;
+
+ s = ppc_intr_disable();
+ __asm __volatile ("mtspr 277,%0; isync" :: "r" (val));
+ ppc_intr_enable(s);
+}
+
u_int64_t
ppc64_mfscomc(void)
{