313 lines
6.3 KiB
C
313 lines
6.3 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 2000 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
amdk6msr.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This module implements code specific to the AMDK6-2 processor
|
||
|
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Todd Carpenter (7/20/00) - create file
|
||
|
|
||
|
Environment:
|
||
|
|
||
|
Kernel mode
|
||
|
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
|
||
|
--*/
|
||
|
#include <ntddk.h>
|
||
|
#include <ntacpi.h>
|
||
|
#include "amdk6.h"
|
||
|
|
||
|
extern LEGACY_GEMINI_SMI LegacyInterface;
|
||
|
extern HalpFixedAcpiDescTable;
|
||
|
|
||
|
PUCHAR ProcessorToBusClockRatioStr[] = {
|
||
|
|
||
|
"4.5x", // 0
|
||
|
"5.0x", // 1
|
||
|
"4.0x", // 2
|
||
|
"5.5x", // 3
|
||
|
"2.0x", // 4
|
||
|
"3.0x", // 5
|
||
|
"6.0x", // 6
|
||
|
"3.5x", // 7
|
||
|
|
||
|
};
|
||
|
|
||
|
NTSTATUS
|
||
|
GetCurrentCpuSpeedMSR (
|
||
|
OUT PULONG CpuSpeed
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
NTSTATUS status;
|
||
|
UCHAR vidANDbf;
|
||
|
ULONG state;
|
||
|
LARGE_INTEGER msrInfo;
|
||
|
|
||
|
DebugAssert(LegacyInterface.GBDT);
|
||
|
DebugAssert(CpuSpeed);
|
||
|
|
||
|
|
||
|
msrInfo.QuadPart = ReadMSR(AMDK6_GEMINI_PSOR_MSR);
|
||
|
|
||
|
//
|
||
|
// VID [20:16 ] and BF [ 2:0 ] --> VID [4:0 ] and BF [7:5 ]
|
||
|
//
|
||
|
|
||
|
vidANDbf = (UCHAR)(((msrInfo.LowPart >> 16) & 0x1f) | ((msrInfo.LowPart & 0x7) << 5));
|
||
|
status = ConvertVidBfValueToGeminiState(vidANDbf, &state);
|
||
|
|
||
|
if (NT_SUCCESS(status)) {
|
||
|
*CpuSpeed = LegacyInterface.GBDT->State[state].CpuFrequency;
|
||
|
}
|
||
|
|
||
|
return status;
|
||
|
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
SetCurrentStateMSR (
|
||
|
ULONG State
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Description:
|
||
|
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NTSTATUS
|
||
|
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
#define STOP_GRANT_TIME_OUT 3 // ISSUE: need to check bus clock to gen this number
|
||
|
|
||
|
LARGE_INTEGER msrInfo;
|
||
|
NTSTATUS status = STATUS_NOT_SUPPORTED;
|
||
|
ULONG esiReturned, geminiState;
|
||
|
UCHAR vidANDbf = 0;
|
||
|
ULONG bvcValue = 0;
|
||
|
|
||
|
|
||
|
DebugAssert(LegacyInterface.EpmIoAddress);
|
||
|
|
||
|
|
||
|
//
|
||
|
// Convert to Gemini State
|
||
|
//
|
||
|
|
||
|
geminiState = CONVERT_PERF_STATE_INDEX(State);
|
||
|
|
||
|
//
|
||
|
// Lookup VID and BF values for geminiState
|
||
|
//
|
||
|
|
||
|
vidANDbf = (LegacyInterface.GBDT->State[geminiState].Vid) |
|
||
|
((LegacyInterface.GBDT->State[geminiState].Bf) << 5);
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// Build BVC value to write to I/O space to initiate transition
|
||
|
//
|
||
|
|
||
|
bvcValue |= (STOP_GRANT_TIME_OUT << 12); // Stop Grant Time-out Counter
|
||
|
bvcValue |= (0x6 << 8); // BVF[11:8] == 0110
|
||
|
bvcValue |= vidANDbf; //
|
||
|
|
||
|
|
||
|
|
||
|
_asm {
|
||
|
|
||
|
//
|
||
|
// Disable bus masters
|
||
|
//
|
||
|
|
||
|
mov edx, [HalpFixedAcpiDescTable + 72]
|
||
|
in al, dx // read PM2_CNT_BLK
|
||
|
mov cl, al // save current PM2_CNT_BLK
|
||
|
or al, 0x1 // set ARB_DIS bit
|
||
|
out dx, al // write PM2_CNT_BLK
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// initiate processor transition
|
||
|
//
|
||
|
|
||
|
mov edx, LegacyInterface.EpmIoAddress
|
||
|
mov eax, bvcValue
|
||
|
out dx, eax
|
||
|
|
||
|
|
||
|
//
|
||
|
// Restore bus master access
|
||
|
//
|
||
|
|
||
|
mov edx, [HalpFixedAcpiDescTable + 72]
|
||
|
mov al, cl
|
||
|
out dx, al
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// BUGBUG: Need to figure out error checking. Should probably go read
|
||
|
// see if PSOR reflects our new vid and bf values.
|
||
|
//
|
||
|
|
||
|
return STATUS_SUCCESS;
|
||
|
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
ReadEpmInfo (
|
||
|
OUT PULONG EpmInfo
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
ULONG emp;
|
||
|
|
||
|
_asm {
|
||
|
|
||
|
mov eax, AMDK6_GEMINI_CPUID_EPM
|
||
|
xor ebx, ebx
|
||
|
xor ecx, ecx
|
||
|
xor edx, edx // will be destroyed by the cpuid
|
||
|
|
||
|
cpuid
|
||
|
mov emp, edx
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
if (ARGUMENT_PRESENT(EpmInfo)) {
|
||
|
*EpmInfo = emp;
|
||
|
}
|
||
|
|
||
|
return STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
EnableGeminiTransitionsMSR (
|
||
|
PULONG BaseAddress
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
ULARGE_INTEGER msrInfo;
|
||
|
|
||
|
DebugAssert(BaseAddress);
|
||
|
|
||
|
|
||
|
//
|
||
|
// EPMR contains I/O block address for perf transitions
|
||
|
//
|
||
|
|
||
|
msrInfo.QuadPart = ReadMSR(AMDK6_GEMINI_EPMR_MSR);
|
||
|
|
||
|
*BaseAddress = (msrInfo.LowPart & ~0xf) + 8;
|
||
|
DebugPrint((INFO, "EnableGeminiTransitionsMSR: Base Address = 0x%x\n", *BaseAddress));
|
||
|
|
||
|
|
||
|
//
|
||
|
// Enable mobile feature base address
|
||
|
//
|
||
|
|
||
|
msrInfo.LowPart |= 0x1;
|
||
|
WriteMSR(AMDK6_GEMINI_EPMR_MSR, msrInfo.QuadPart);
|
||
|
|
||
|
return STATUS_SUCCESS;
|
||
|
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
DisplayEPM (
|
||
|
IN ULONG Epm
|
||
|
)
|
||
|
{
|
||
|
|
||
|
DebugPrint((MAXTRACE, "Enhanced Power Management Information (0x%x):\n", Epm));
|
||
|
DebugPrint((MAXTRACE, " Temperature Sensor: %sSupported\n", (Epm & 0x1) ? "" : "NOT "));
|
||
|
DebugPrint((MAXTRACE, " Bus Divisor Control: %sSupported\n", (Epm & 0x2) ? "" : "NOT "));
|
||
|
DebugPrint((MAXTRACE, " Voltage Id control: %sSupported\n", (Epm & 0x4) ? "" : "NOT "));
|
||
|
DebugPrint((MAXTRACE, "\n"));
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
DisplayEPMR (
|
||
|
IN ULONG Epmr
|
||
|
)
|
||
|
{
|
||
|
|
||
|
DebugPrint((MAXTRACE, "Enhanced Power Management Register (0x%x):\n", Epmr));
|
||
|
DebugPrint((MAXTRACE, " Mobile Feature Base Address = %sEnabled\n", (Epmr & 0x1) ? "" : "NOT "));
|
||
|
DebugPrint((MAXTRACE, " Generate Special Bus Cycle = %sEnabled\n", (Epmr & 0x2) ? "" : "NOT "));
|
||
|
DebugPrint((MAXTRACE, " I/O Base Address = 0x%x\n", ((Epmr >> 4) & 0xffff)));
|
||
|
DebugPrint((MAXTRACE, "\n"));
|
||
|
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
DisplayPSOR (
|
||
|
IN ULONG Psor
|
||
|
)
|
||
|
{
|
||
|
|
||
|
DebugPrint((MAXTRACE, "Processor State Observability (0x%x):\n", Psor));
|
||
|
DebugPrint((MAXTRACE, " Bus Frequency Divisor (Internal) = 0x%x (%s)\n", (Psor & 0x3),
|
||
|
ProcessorToBusClockRatioStr[(Psor & 0x3)]));
|
||
|
DebugPrint((MAXTRACE, " Processor Stepping Id = 0x%x\n", ((Psor >> 4) & 0xf)));
|
||
|
DebugPrint((MAXTRACE, " L2 Cache Present = %s\n", (Psor & 0x256) ? "No" : "Yes"));
|
||
|
DebugPrint((MAXTRACE, " Voltage Id = 0x%x\n", ((Psor >> 16) & 0x1f)));
|
||
|
DebugPrint((MAXTRACE, " Bus Frequency Divisor (External) = 0x%x (%s)\n", ((Psor >> 21) & 0x3),
|
||
|
ProcessorToBusClockRatioStr[((Psor >> 21) & 0x3)]));
|
||
|
DebugPrint((MAXTRACE, "\n"));
|
||
|
}
|