summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUwe Stuehler <uwe@cvs.openbsd.org>2006-03-08 03:33:22 +0000
committerUwe Stuehler <uwe@cvs.openbsd.org>2006-03-08 03:33:22 +0000
commit86a2e554404338ac982b3b81b956f08e324aebc0 (patch)
tree2440e43a112194e25af13ccd000055593210af52
parent04c30bf2d76475394d2e5b4f46c78daa68de854b (diff)
Patch from Gordon Klock to update AMD PowerNow K8 support on i386,
and to add amd64 K8 support from FreeBSD.
-rw-r--r--sys/arch/amd64/amd64/identcpu.c34
-rw-r--r--sys/arch/amd64/amd64/powernow-k8.c404
-rw-r--r--sys/arch/amd64/conf/files.amd643
-rw-r--r--sys/arch/amd64/include/cpu.h6
-rw-r--r--sys/arch/i386/i386/machdep.c4
-rw-r--r--sys/arch/i386/i386/powernow-k8.c60
6 files changed, 464 insertions, 47 deletions
diff --git a/sys/arch/amd64/amd64/identcpu.c b/sys/arch/amd64/amd64/identcpu.c
index e66a1f8d3e3..d0e1381527f 100644
--- a/sys/arch/amd64/amd64/identcpu.c
+++ b/sys/arch/amd64/amd64/identcpu.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: identcpu.c,v 1.7 2006/03/07 05:21:40 jsg Exp $ */
+/* $OpenBSD: identcpu.c,v 1.8 2006/03/08 03:33:21 uwe Exp $ */
/* $NetBSD: identcpu.c,v 1.1 2003/04/26 18:39:28 fvdl Exp $ */
/*
@@ -94,6 +94,18 @@ const struct {
{ CPUIDECX_SSE3, "SSE3" }
};
+const struct {
+ u_int32_t mask;
+ const char * name;
+} amd_pn_flags[] = {
+ { 0x01, "TS"},
+ { 0x02, "FID"},
+ { 0x04, "VID"},
+ { 0x08, "TTP"},
+ { 0x10, "TM"},
+ { 0x20, "STC"}
+};
+
int
cpu_amd64speed(int *freq)
{
@@ -105,13 +117,14 @@ void
identifycpu(struct cpu_info *ci)
{
u_int64_t last_tsc;
- u_int32_t dummy, val;
+ u_int32_t dummy, val, pnfeatset;
u_int32_t brand[12];
int i, max;
char *brandstr_from, *brandstr_to;
int skipspace;
CPUID(1, ci->ci_signature, val, dummy, ci->ci_feature_flags);
+ CPUID(0x80000000, pnfeatset, dummy, dummy, dummy);
CPUID(0x80000001, dummy, dummy, dummy, ci->ci_feature_eflags);
CPUID(0x80000002, brand[0], brand[1], brand[2], brand[3]);
@@ -168,6 +181,23 @@ identifycpu(struct cpu_info *ci)
printf("\n");
x86_print_cacheinfo(ci);
+
+#ifndef MULTIPROCESSOR
+ if (pnfeatset > 0x80000007) {
+ CPUID(0x80000007, dummy, dummy, dummy, pnfeatset);
+ printf("%s: AMD Powernow:", ci->ci_dev->dv_xname);
+ for (i = 0; i < 6; i++) {
+ if (pnfeatset & amd_pn_flags[i].mask)
+ printf(" %s", amd_pn_flags[i].name);
+ }
+ printf("\n");
+
+ if (pnfeatset & 0x06) {
+ if ((ci->ci_signature & 0xF00) == 0xf00)
+ k8_powernow_init();
+ }
+ }
+#endif
}
void
diff --git a/sys/arch/amd64/amd64/powernow-k8.c b/sys/arch/amd64/amd64/powernow-k8.c
new file mode 100644
index 00000000000..29c4f4f15da
--- /dev/null
+++ b/sys/arch/amd64/amd64/powernow-k8.c
@@ -0,0 +1,404 @@
+/* $OpenBSD: powernow-k8.c,v 1.1 2006/03/08 03:33:21 uwe Exp $ */
+/*
+ * Copyright (c) 2004 Martin Végiard.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Copyright (c) 2004-2005 Bruno Ducrot
+ * Copyright (c) 2004 FUKUDA Nobuhiko <nfukuda@spa.is.uec.ac.jp>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/* AMD POWERNOW K8 driver */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/sysctl.h>
+
+#include <dev/isa/isareg.h>
+#include <amd64/include/isa_machdep.h>
+
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/bus.h>
+
+#define BIOS_START 0xe0000
+#define BIOS_LEN 0x20000
+
+extern int cpuspeed;
+
+/*
+ * MSRs and bits used by Powernow technology
+ */
+#define MSR_AMDK7_FIDVID_CTL 0xc0010041
+#define MSR_AMDK7_FIDVID_STATUS 0xc0010042
+
+/* Bitfields used by K8 */
+
+#define PN8_CTR_FID(x) ((x) & 0x3f)
+#define PN8_CTR_VID(x) (((x) & 0x1f) << 8)
+#define PN8_CTR_PENDING(x) (((x) & 1) << 32)
+
+#define PN8_STA_CFID(x) ((x) & 0x3f)
+#define PN8_STA_SFID(x) (((x) >> 8) & 0x3f)
+#define PN8_STA_MFID(x) (((x) >> 16) & 0x3f)
+#define PN8_STA_PENDING(x) (((x) >> 31) & 0x01)
+#define PN8_STA_CVID(x) (((x) >> 32) & 0x1f)
+#define PN8_STA_SVID(x) (((x) >> 40) & 0x1f)
+#define PN8_STA_MVID(x) (((x) >> 48) & 0x1f)
+
+/* Reserved1 to powernow k8 configuration */
+#define PN8_PSB_TO_RVO(x) ((x) & 0x03)
+#define PN8_PSB_TO_IRT(x) (((x) >> 2) & 0x03)
+#define PN8_PSB_TO_MVS(x) (((x) >> 4) & 0x03)
+#define PN8_PSB_TO_BATT(x) (((x) >> 6) & 0x03)
+
+/* ACPI ctr_val status register to powernow k8 configuration */
+#define ACPI_PN8_CTRL_TO_FID(x) ((x) & 0x3f)
+#define ACPI_PN8_CTRL_TO_VID(x) (((x) >> 6) & 0x1f)
+#define ACPI_PN8_CTRL_TO_VST(x) (((x) >> 11) & 0x1f)
+#define ACPI_PN8_CTRL_TO_MVS(x) (((x) >> 18) & 0x03)
+#define ACPI_PN8_CTRL_TO_PLL(x) (((x) >> 20) & 0x7f)
+#define ACPI_PN8_CTRL_TO_RVO(x) (((x) >> 28) & 0x03)
+#define ACPI_PN8_CTRL_TO_IRT(x) (((x) >> 30) & 0x03)
+
+#define WRITE_FIDVID(fid, vid, ctrl) \
+ wrmsr(MSR_AMDK7_FIDVID_CTL, \
+ (((ctrl) << 32) | (1ULL << 16) | ((vid) << 8) | (fid)))
+
+
+#define COUNT_OFF_IRT(irt) DELAY(10 * (1 << (irt)))
+#define COUNT_OFF_VST(vst) DELAY(20 * (vst))
+
+#define FID_TO_VCO_FID(fid) \
+ (((fid) < 8) ? (8 + ((fid) << 1)) : (fid))
+
+#define POWERNOW_MAX_STATES 16
+
+struct k8pnow_state {
+ int freq;
+ uint8_t fid;
+ uint8_t vid;
+};
+
+struct k8pnow_cpu_state {
+ struct k8pnow_state state_table[POWERNOW_MAX_STATES];
+ unsigned int n_states;
+ unsigned int sgtc;
+ unsigned int vst;
+ unsigned int mvs;
+ unsigned int pll;
+ unsigned int rvo;
+ unsigned int irt;
+ int low;
+};
+
+struct psb_s {
+ char signature[10]; /* AMDK7PNOW! */
+ uint8_t version;
+ uint8_t flags;
+ uint16_t ttime; /* Min Settling time */
+ uint8_t reserved;
+ uint8_t n_pst;
+};
+
+struct pst_s {
+ uint32_t cpuid;
+ uint8_t pll;
+ uint8_t fid;
+ uint8_t vid;
+ uint8_t n_states;
+};
+
+struct k8pnow_cpu_state *k8pnow_current_state;
+
+/*
+ * Prototypes
+ */
+int k8pnow_read_pending_wait(uint64_t *);
+int k8pnow_decode_pst(struct k8pnow_cpu_state *, uint8_t *);
+int k8pnow_states(struct k8pnow_cpu_state *, uint32_t, unsigned int,
+ unsigned int);
+
+int k8pnow_read_pending_wait(uint64_t * status) {
+ unsigned int i = 1000;
+ while(i--) {
+ *status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
+ if (!PN8_STA_PENDING(*status))
+ return 0;
+
+ }
+ printf("k8pnow_read_pending_wait: change pending stuck.\n");
+ return 1;
+}
+
+int
+k8_powernow_setperf(int level)
+{
+ unsigned int i, low, high, freq;
+ uint64_t status;
+ int cfid, cvid, fid = 0, vid = 0;
+ int rvo;
+ u_int val;
+ struct k8pnow_cpu_state *cstate;
+
+ /*
+ * We dont do a k8pnow_read_pending_wait here, need to ensure that the
+ * change pending bit isn't stuck,
+ */
+ status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
+ if (PN8_STA_PENDING(status))
+ return 1;
+ cfid = PN8_STA_CFID(status);
+ cvid = PN8_STA_CVID(status);
+
+ cstate = k8pnow_current_state;
+ low = cstate->state_table[0].freq;
+ high = cstate->state_table[cstate->n_states-1].freq;
+
+ freq = low + (high - low) * level / 100;
+
+ for (i = 0; i < cstate->n_states; i++) {
+ if (cstate->state_table[i].freq >= freq) {
+ fid = cstate->state_table[i].fid;
+ vid = cstate->state_table[i].vid;
+ break;
+ }
+ }
+
+ if (fid == cfid && vid == cvid)
+ return (0);
+
+ /*
+ * Phase 1: Raise core voltage to requested VID if frequency is
+ * going up.
+ */
+ while (cvid > vid) {
+ val = cvid - (1 << cstate->mvs);
+ WRITE_FIDVID(cfid, (val > 0) ? val : 0, 1ULL);
+ if (k8pnow_read_pending_wait(&status))
+ return 1;
+ cvid = PN8_STA_CVID(status);
+ COUNT_OFF_VST(cstate->vst);
+ }
+
+ /* ... then raise to voltage + RVO (if required) */
+ for (rvo = cstate->rvo; rvo > 0 && cvid > 0; --rvo) {
+ /* XXX It's not clear from spec if we have to do that
+ * in 0.25 step or in MVS. Therefore do it as it's done
+ * under Linux */
+ WRITE_FIDVID(cfid, cvid - 1, 1ULL);
+ if (k8pnow_read_pending_wait(&status))
+ return 1;
+ cvid = PN8_STA_CVID(status);
+ COUNT_OFF_VST(cstate->vst);
+ }
+
+ /* Phase 2: change to requested core frequency */
+ if (cfid != fid) {
+ u_int vco_fid, vco_cfid;
+
+ vco_fid = FID_TO_VCO_FID(fid);
+ vco_cfid = FID_TO_VCO_FID(cfid);
+
+ while (abs(vco_fid - vco_cfid) > 2) {
+ if (fid > cfid) {
+ if (cfid > 6)
+ val = cfid + 2;
+ else
+ val = FID_TO_VCO_FID(cfid) + 2;
+ } else
+ val = cfid - 2;
+ WRITE_FIDVID(val, cvid, (uint64_t)cstate->pll * 1000 / 5);
+
+ if (k8pnow_read_pending_wait(&status))
+ return 1;
+ cfid = PN8_STA_CFID(status);
+ COUNT_OFF_IRT(cstate->irt);
+
+ vco_cfid = FID_TO_VCO_FID(cfid);
+ }
+
+ WRITE_FIDVID(fid, cvid, (uint64_t) cstate->pll * 1000 / 5);
+ if (k8pnow_read_pending_wait(&status))
+ return 1;
+ cfid = PN8_STA_CFID(status);
+ COUNT_OFF_IRT(cstate->irt);
+ }
+
+ /* Phase 3: change to requested voltage */
+ if (cvid != vid) {
+ WRITE_FIDVID(cfid, vid, 1ULL);
+ if (k8pnow_read_pending_wait(&status))
+ return 1;
+ cvid = PN8_STA_CVID(status);
+ COUNT_OFF_VST(cstate->vst);
+ }
+
+ /* Check if transition failed. */
+ if (cfid != fid || cvid != vid)
+ return (1);
+
+ cpuspeed = cstate->state_table[i].freq;
+ return (0);
+}
+
+/*
+ * Given a set of pair of fid/vid, and number of performance states,
+ * compute state_table via an insertion sort.
+ */
+int
+k8pnow_decode_pst(struct k8pnow_cpu_state *cstate, uint8_t *p)
+{
+ int i, j, n;
+ struct k8pnow_state state;
+ for (n = 0, i = 0; i < cstate->n_states; i++) {
+ state.fid = *p++;
+ state.vid = *p++;
+
+ /*
+ * The minimum supported frequency per the data sheet is 800MHz
+ * The maximum supported frequency is 5000MHz.
+ */
+ state.freq = 800 + state.fid * 100;
+ j = n;
+ while (j > 0 && cstate->state_table[j - 1].freq > state.freq) {
+ memcpy(&cstate->state_table[j],
+ &cstate->state_table[j - 1],
+ sizeof(struct k8pnow_state));
+ --j;
+ }
+ memcpy(&cstate->state_table[j], &state,
+ sizeof(struct k8pnow_state));
+ n++;
+ }
+ return 1;
+}
+
+int
+k8pnow_states(struct k8pnow_cpu_state *cstate, uint32_t cpusig,
+ unsigned int fid, unsigned int vid)
+{
+ struct psb_s *psb;
+ struct pst_s *pst;
+ uint8_t *p;
+ int i;
+
+ for (p = (u_int8_t *)ISA_HOLE_VADDR(BIOS_START);
+ p < (u_int8_t *)ISA_HOLE_VADDR(BIOS_START + BIOS_LEN); p += 16) {
+ if (memcmp(p, "AMDK7PNOW!", 10) == 0) {
+ psb = (struct psb_s *)p;
+ if (psb->version != 0x14)
+ return 0;
+
+ cstate->vst = psb->ttime;
+ cstate->rvo = PN8_PSB_TO_RVO(psb->reserved);
+ cstate->irt = PN8_PSB_TO_IRT(psb->reserved);
+ cstate->mvs = PN8_PSB_TO_MVS(psb->reserved);
+ cstate->low = PN8_PSB_TO_BATT(psb->reserved);
+ p+= sizeof(struct psb_s);
+
+ for(i = 0; i < psb->n_pst; ++i) {
+ pst = (struct pst_s *) p;
+
+ cstate->pll = pst->pll;
+ cstate->n_states = pst->n_states;
+ if (cpusig == pst->cpuid &&
+ pst->fid == fid && pst->vid == vid) {
+ return (k8pnow_decode_pst(cstate,
+ p+= sizeof (struct pst_s)));
+ }
+ p += sizeof(struct pst_s) + 2 * cstate->n_states;
+ }
+ }
+ }
+
+ return 0;
+
+}
+
+void
+k8_powernow_init(void)
+{
+ uint64_t status;
+ u_int maxfid, maxvid, i;
+ struct k8pnow_cpu_state *cstate;
+ struct k8pnow_state *state;
+ struct cpu_info * ci;
+ char * techname = NULL;
+ ci = curcpu();
+
+ cstate = malloc(sizeof(struct k8pnow_cpu_state), M_DEVBUF, M_NOWAIT);
+ if (!cstate)
+ return;
+
+ status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
+ maxfid = PN8_STA_MFID(status);
+ maxvid = PN8_STA_MVID(status);
+
+ /*
+ * If start FID is different to max FID, then it is a
+ * mobile processor. If not, it is a low powered desktop
+ * processor.
+ */
+ if (PN8_STA_SFID(status) != PN8_STA_MFID(status))
+ techname = "PowerNow! K8";
+ else
+ techname = "Cool`n'Quiet K8";
+
+ if (k8pnow_states(cstate, ci->ci_signature, maxfid, maxvid)) {
+ if (cstate->n_states) {
+ printf("%s: AMD %s available states ",
+ ci->ci_dev->dv_xname, techname);
+ for(i= 0; i < cstate->n_states; i++) {
+ state = &cstate->state_table[i];
+ printf("%c%d", i==0 ? '(' : ',',
+ state->freq);
+ }
+ printf(")\n");
+ k8pnow_current_state = cstate;
+ cpu_setperf = k8_powernow_setperf;
+ }
+ }
+}
diff --git a/sys/arch/amd64/conf/files.amd64 b/sys/arch/amd64/conf/files.amd64
index 7d40cbcf4a3..9655fff362e 100644
--- a/sys/arch/amd64/conf/files.amd64
+++ b/sys/arch/amd64/conf/files.amd64
@@ -1,4 +1,4 @@
-# $OpenBSD: files.amd64,v 1.19 2006/02/12 19:55:36 miod Exp $
+# $OpenBSD: files.amd64,v 1.20 2006/03/08 03:33:21 uwe Exp $
maxpartitions 16
maxusers 2 16 128
@@ -56,6 +56,7 @@ file arch/amd64/amd64/kgdb_machdep.c kgdb
file arch/amd64/isa/clock.c
file dev/clock_subr.c
+file arch/amd64/amd64/powernow-k8.c
include "dev/mii/files.mii"
diff --git a/sys/arch/amd64/include/cpu.h b/sys/arch/amd64/include/cpu.h
index d48c00bf267..372a26d080c 100644
--- a/sys/arch/amd64/include/cpu.h
+++ b/sys/arch/amd64/include/cpu.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.h,v 1.17 2005/12/13 00:18:19 jsg Exp $ */
+/* $OpenBSD: cpu.h,v 1.18 2006/03/08 03:33:21 uwe Exp $ */
/* $NetBSD: cpu.h,v 1.1 2003/04/26 18:39:39 fvdl Exp $ */
/*-
@@ -305,6 +305,10 @@ void kgdb_port_init(void);
void x86_bus_space_init(void);
void x86_bus_space_mallocok(void);
+/* powernow-k8.c */
+void k8_powernow_init(void);
+int k8_powernow_setperf(int);
+
#endif /* _KERNEL */
/*
diff --git a/sys/arch/i386/i386/machdep.c b/sys/arch/i386/i386/machdep.c
index a26e4980b54..79edd4e2a7a 100644
--- a/sys/arch/i386/i386/machdep.c
+++ b/sys/arch/i386/i386/machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: machdep.c,v 1.341 2006/03/07 05:18:08 jsg Exp $ */
+/* $OpenBSD: machdep.c,v 1.342 2006/03/08 03:33:21 uwe Exp $ */
/* $NetBSD: machdep.c,v 1.214 1996/11/10 03:16:17 thorpej Exp $ */
/*-
@@ -1430,6 +1430,7 @@ amd_family6_setup(struct cpu_info *ci)
pagezero = sse2_pagezero;
else
pagezero = i686_pagezero;
+#if !defined(MULTIPROCESSOR)
cpuid(0x80000000, regs);
if (regs[0] > 0x80000007) {
cpuid(0x80000007, regs);
@@ -1451,6 +1452,7 @@ amd_family6_setup(struct cpu_info *ci)
}
}
}
+#endif
#endif
}
diff --git a/sys/arch/i386/i386/powernow-k8.c b/sys/arch/i386/i386/powernow-k8.c
index 16c05e1690c..4ee4d61811c 100644
--- a/sys/arch/i386/i386/powernow-k8.c
+++ b/sys/arch/i386/i386/powernow-k8.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: powernow-k8.c,v 1.3 2005/11/26 11:22:12 tedu Exp $ */
+/* $OpenBSD: powernow-k8.c,v 1.4 2006/03/08 03:33:21 uwe Exp $ */
/*
* Copyright (c) 2004 Martin Végiard.
* All rights reserved.
@@ -112,29 +112,6 @@
#define FID_TO_VCO_FID(fid) \
(((fid) < 8) ? (8 + ((fid) << 1)) : (fid))
-/*
- * Divide each value by 10 to get the processor multiplier.
- */
-
-static int pn8_fid_to_mult[32] = {
- 40, 50, 60, 70, 80, 90, 100, 110,
- 120, 130, 140, 150, 160, 170, 180, 190,
- 220, 230, 240, 250, 260, 270, 280, 290,
- 300, 310, 320, 330, 340, 350,
-};
-
-/*
- * Units are in mV.
- */
-
-/* Desktop and Mobile VRM (K8) */
-static int pn8_vid_to_volts[] = {
- 1550, 1525, 1500, 1475, 1450, 1425, 1400, 1375,
- 1350, 1325, 1300, 1275, 1250, 1225, 1200, 1175,
- 1150, 1125, 1100, 1075, 1050, 1025, 1000, 975,
- 950, 925, 900, 875, 850, 825, 800, 0,
-};
-
#define POWERNOW_MAX_STATES 16
struct k8pnow_state {
@@ -146,7 +123,6 @@ struct k8pnow_state {
struct k8pnow_cpu_state {
struct k8pnow_state state_table[POWERNOW_MAX_STATES];
unsigned int n_states;
- unsigned int fsb;
unsigned int sgtc;
unsigned int vst;
unsigned int mvs;
@@ -154,7 +130,6 @@ struct k8pnow_cpu_state {
unsigned int rvo;
unsigned int irt;
int low;
- int *vid_to_volts;
};
struct psb_s {
@@ -174,7 +149,7 @@ struct pst_s {
uint8_t n_states;
};
-struct k8pnow_cpu_state *k8pnow_current_state[I386_MAXPROCS];
+struct k8pnow_cpu_state *k8pnow_current_state = NULL;
/*
* Prototypes
@@ -216,7 +191,7 @@ k8_powernow_setperf(int level)
cfid = PN8_STA_CFID(status);
cvid = PN8_STA_CVID(status);
- cstate = k8pnow_current_state[cpu_number()];
+ cstate = k8pnow_current_state;
low = cstate->state_table[0].freq;
high = cstate->state_table[cstate->n_states-1].freq;
@@ -273,8 +248,7 @@ k8_powernow_setperf(int level)
val = FID_TO_VCO_FID(cfid) + 2;
} else
val = cfid - 2;
- WRITE_FIDVID(val, cvid, cstate->pll *
- (uint64_t)cstate->fsb);
+ WRITE_FIDVID(val, cvid, (uint64_t)cstate->pll * 1000 / 5);
if (k8pnow_read_pending_wait(&status))
return 1;
@@ -284,7 +258,7 @@ k8_powernow_setperf(int level)
vco_cfid = FID_TO_VCO_FID(cfid);
}
- WRITE_FIDVID(fid, cvid, cstate->pll * (uint64_t)cstate->fsb);
+ WRITE_FIDVID(fid, cvid, (uint64_t) cstate->pll * 1000 / 5);
if (k8pnow_read_pending_wait(&status))
return 1;
cfid = PN8_STA_CFID(status);
@@ -304,7 +278,7 @@ k8_powernow_setperf(int level)
if (cfid != fid || cvid != vid)
return (1);
- pentium_mhz = ((cstate->state_table[i].freq / 100000)+1)*100;
+ pentium_mhz = cstate->state_table[i].freq;
return (0);
}
@@ -320,8 +294,12 @@ k8pnow_decode_pst(struct k8pnow_cpu_state *cstate, uint8_t *p)
for (n = 0, i = 0; i < cstate->n_states; i++) {
state.fid = *p++;
state.vid = *p++;
-
- state.freq = 100 * pn8_fid_to_mult[state.fid >>1] *cstate->fsb;
+
+ /*
+ * The minimum supported frequency per the data sheet is 800MHz
+ * The maximum supported frequency is 5000MHz.
+ */
+ state.freq = 800 + state.fid * 100;
j = n;
while (j > 0 && cstate->state_table[j - 1].freq > state.freq) {
memcpy(&cstate->state_table[j],
@@ -382,13 +360,16 @@ void
k8_powernow_init(void)
{
uint64_t status;
- u_int maxfid, maxvid, currentfid, i;
+ u_int maxfid, maxvid, i;
struct k8pnow_cpu_state *cstate;
struct k8pnow_state *state;
struct cpu_info * ci;
char * techname = NULL;
ci = curcpu();
+ if(k8pnow_current_state)
+ return;
+
cstate = malloc(sizeof(struct k8pnow_cpu_state), M_DEVBUF, M_NOWAIT);
if (!cstate)
return;
@@ -396,12 +377,7 @@ k8_powernow_init(void)
status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
maxfid = PN8_STA_MFID(status);
maxvid = PN8_STA_MVID(status);
- currentfid = PN8_STA_CFID(status);
-
- CPU_CLOCKUPDATE();
- cstate->fsb = pentium_base_tsc/ 100000/ pn8_fid_to_mult[currentfid>>1];
- cstate->vid_to_volts = pn8_vid_to_volts;
/*
* If start FID is different to max FID, then it is a
* mobile processor. If not, it is a low powered desktop
@@ -419,10 +395,10 @@ k8_powernow_init(void)
for(i= 0; i < cstate->n_states; i++) {
state = &cstate->state_table[i];
printf("%c%d", i==0 ? '(' : ',',
- ((state->freq / 100000)+1)*100);
+ state->freq);
}
printf(")\n");
- k8pnow_current_state[cpu_number()] = cstate;
+ k8pnow_current_state = cstate;
cpu_setperf = k8_powernow_setperf;
}
}