diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/i386/i386/powernow-k7.c | 111 |
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"; |