summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/i386/i386/powernow-k7.c111
1 files changed, 107 insertions, 4 deletions
diff --git a/sys/arch/i386/i386/powernow-k7.c b/sys/arch/i386/i386/powernow-k7.c
index ca5f4068451..4aade83b8aa 100644
--- a/sys/arch/i386/i386/powernow-k7.c
+++ b/sys/arch/i386/i386/powernow-k7.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: powernow-k7.c,v 1.31 2007/04/24 17:12:26 gwk Exp $ */
+/* $OpenBSD: powernow-k7.c,v 1.32 2007/07/27 03:03:37 gwk Exp $ */
/*
* Copyright (c) 2004 Martin Végiard.
@@ -41,6 +41,13 @@
#include <dev/isa/isareg.h>
#include <i386/isa/isa_machdep.h>
+#include "acpicpu.h"
+
+#if NACPICPU > 0
+#include <dev/acpi/acpidev.h>
+#include <dev/acpi/acpivar.h>
+#endif
+
#define BIOS_START 0xe0000
#define BIOS_LEN 0x20000
#define BIOS_STEP 16
@@ -75,6 +82,7 @@
/*
* ACPI ctr_val status register to powernow k7 configuration
*/
+#define PN7_ACPI_CTRL_TO_FID(x) ((x) & 0x1f)
#define PN7_ACPI_CTRL_TO_VID(x) (((x) >> 5) & 0x1f)
#define PN7_ACPI_CTRL_TO_SGTC(x) (((x) >> 10) & 0xffff)
@@ -133,6 +141,13 @@ int k7pnow_decode_pst(struct k7pnow_cpu_state *, uint8_t *, int);
int k7pnow_states(struct k7pnow_cpu_state *, uint32_t, unsigned int,
unsigned int);
+#if NACPICPU > 0
+int k7pnow_acpi_init(struct k7pnow_cpu_state * cstate, uint64_t status);
+int k7pnow_acpi_states(struct k7pnow_cpu_state * cstate,
+ struct acpicpu_pss *pss, int nstates, uint64_t status);
+void k7pnow_acpi_pss_changed(struct acpicpu_pss *pss, int npss);
+#endif
+
void
k7_powernow_setperf(int level)
{
@@ -278,6 +293,87 @@ k7pnow_states(struct k7pnow_cpu_state *cstate, uint32_t cpusig,
return 0;
}
+#if NACPICPU > 0
+
+int
+k7pnow_acpi_states(struct k7pnow_cpu_state * cstate, struct acpicpu_pss *pss,
+ int nstates, uint64_t status)
+{
+ struct k7pnow_state state;
+ int j, k, n;
+ uint32_t ctrl;
+
+ k = -1;
+ for (n = 0; n < cstate->n_states; n++) {
+ if (status == pss[n].pss_status)
+ k = n;
+ ctrl = pss[n].pss_ctrl;
+ state.fid = PN7_ACPI_CTRL_TO_FID(ctrl);
+ state.vid = PN7_ACPI_CTRL_TO_VID(ctrl);
+
+ state.freq = pss[n].pss_core_freq;
+ 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 k7pnow_state));
+ --j;
+ }
+ memcpy(&cstate->state_table[j], &state,
+ sizeof(struct k7pnow_state));
+ }
+ return k;
+}
+
+void
+k7pnow_acpi_pss_changed(struct acpicpu_pss *pss, int npss)
+{
+ int curs;
+ struct k7pnow_cpu_state *cstate;
+ uint32_t ctrl;
+ uint64_t status;
+
+ status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
+ cstate = k7pnow_current_state;
+
+ curs = k7pnow_acpi_states(cstate, pss, npss, status);
+ ctrl = pss[curs].pss_ctrl;
+ cstate->sgtc = PN7_ACPI_CTRL_TO_SGTC(ctrl);
+ cstate->n_states = npss;
+}
+
+int
+k7pnow_acpi_init(struct k7pnow_cpu_state *cstate, uint64_t status)
+{
+ int curs;
+ uint32_t ctrl;
+ struct acpicpu_pss *pss;
+ int mfid;
+
+ cstate->n_states = acpicpu_fetch_pss(&pss);
+ if (cstate->n_states == 0)
+ return 0;
+
+ /*
+ * XXX: Some BIOS supplied _PSS implementations have the wrong
+ * maximum frequency, if we encounter one of these punt and
+ * hope the legacy tables have correct values.
+ */
+ mfid = PN7_STA_MFID(status);
+ if (mfid != cstate->state_table[cstate->n_states - 1].fid) {
+ return 0;
+ }
+ curs = k7pnow_acpi_states(cstate, pss, cstate->n_states, status);
+
+ acpicpu_set_notify(k7pnow_acpi_pss_changed);
+ ctrl = pss[curs].pss_ctrl;
+ cstate->sgtc = PN7_ACPI_CTRL_TO_SGTC(ctrl);
+
+ return 1;
+}
+
+#endif /* NACPICPU */
+
void
k7_powernow_init(void)
{
@@ -321,9 +417,16 @@ k7_powernow_init(void)
cstate->fsb = cpuspeed / (k7pnow_fid_to_mult[currentfid]/10);
- /* if the base CPUID signature fails to match try, the extended one */
- if (!k7pnow_states(cstate, ci->ci_signature, maxfid, startvid))
- k7pnow_states(cstate, regs[0], maxfid, startvid);
+#if NACPICPU > 0
+ /* If we have it try ACPI */
+ if (!k7pnow_acpi_init(cstate, status))
+#endif
+ {
+ /* if the base CPUID signature fails to match try, the extended one */
+ if (!k7pnow_states(cstate, ci->ci_signature, maxfid, startvid))
+ k7pnow_states(cstate, regs[0], maxfid, startvid);
+ }
+
if (cstate->n_states) {
if (cstate->flags & PN7_FLAG_DESKTOP_VRM)
techname = "Cool'n'Quiet K7";