blob: f3825dd9287b8588c1cf1404719ba0ad26a2fb0d [file] [log] [blame]
/* $NoKeywords:$ */
/**
* @file
*
* ACPI S3 Support routines
*
* Contains routines needed for supporting resume from the ACPI S3 sleep state.
*
* @xrefitem bom "File Content Label" "Release Content"
* @e project: AGESA
* @e sub-project: Interface
* @e \$Revision: 35136 $ @e \$Date: 2010-07-16 11:29:48 +0800 (Fri, 16 Jul 2010) $
*
*/
/*
*****************************************************************************
*
* Copyright (c) 2011, Advanced Micro Devices, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of Advanced Micro Devices, Inc. nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 ADVANCED MICRO DEVICES, INC. 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.
*
* ***************************************************************************
*
*/
/*----------------------------------------------------------------------------------------
* M O D U L E S U S E D
*----------------------------------------------------------------------------------------
*/
#include "AGESA.h"
#include "amdlib.h"
#include "Ids.h"
#include "mm.h"
#include "mn.h"
#include "S3.h"
#include "mfs3.h"
#include "GeneralServices.h"
#include "cpuServices.h"
#include "Filecode.h"
CODE_GROUP (G1_PEICC)
RDATA_GROUP (G1_PEICC)
#define FILECODE PROC_CPU_S3_FILECODE
/*----------------------------------------------------------------------------------------
* D E F I N I T I O N S A N D M A C R O S
*----------------------------------------------------------------------------------------
*/
/*----------------------------------------------------------------------------------------
* T Y P E D E F S A N D S T R U C T U R E S
*----------------------------------------------------------------------------------------
*/
/*----------------------------------------------------------------------------------------
* P R O T O T Y P E S O F L O C A L F U N C T I O N S
*----------------------------------------------------------------------------------------
*/
VOID
SaveDeviceContext (
IN DEVICE_BLOCK_HEADER *DeviceList,
IN CALL_POINTS CallPoint,
OUT UINT32 *ActualBufferSize,
IN AMD_CONFIG_PARAMS *StdHeader
);
VOID
SavePciDevice (
IN AMD_CONFIG_PARAMS *StdHeader,
IN PCI_DEVICE_DESCRIPTOR *Device,
IN CALL_POINTS CallPoint,
IN OUT VOID **OrMask
);
VOID
SaveConditionalPciDevice (
IN AMD_CONFIG_PARAMS *StdHeader,
IN CONDITIONAL_PCI_DEVICE_DESCRIPTOR *Device,
IN CALL_POINTS CallPoint,
IN OUT VOID **OrMask
);
VOID
SaveMsrDevice (
IN AMD_CONFIG_PARAMS *StdHeader,
IN MSR_DEVICE_DESCRIPTOR *Device,
IN CALL_POINTS CallPoint,
IN OUT UINT64 **OrMask
);
VOID
SaveConditionalMsrDevice (
IN AMD_CONFIG_PARAMS *StdHeader,
IN CONDITIONAL_MSR_DEVICE_DESCRIPTOR *Device,
IN CALL_POINTS CallPoint,
IN OUT UINT64 **OrMask
);
VOID
RestorePciDevice (
IN AMD_CONFIG_PARAMS *StdHeader,
IN PCI_DEVICE_DESCRIPTOR *Device,
IN CALL_POINTS CallPoint,
IN OUT VOID **OrMask
);
VOID
RestoreConditionalPciDevice (
IN AMD_CONFIG_PARAMS *StdHeader,
IN CONDITIONAL_PCI_DEVICE_DESCRIPTOR *Device,
IN CALL_POINTS CallPoint,
IN OUT VOID **OrMask
);
VOID
RestoreMsrDevice (
IN AMD_CONFIG_PARAMS *StdHeader,
IN MSR_DEVICE_DESCRIPTOR *Device,
IN CALL_POINTS CallPoint,
IN OUT UINT64 **OrMask
);
VOID
RestoreConditionalMsrDevice (
IN AMD_CONFIG_PARAMS *StdHeader,
IN CONDITIONAL_MSR_DEVICE_DESCRIPTOR *Device,
IN CALL_POINTS CallPoint,
IN OUT UINT64 **OrMask
);
/*----------------------------------------------------------------------------------------
* E X P O R T E D F U N C T I O N S
*----------------------------------------------------------------------------------------
*/
/*---------------------------------------------------------------------------------------*/
/**
* Saves all devices in the given device list.
*
* This traverses the entire device list twice. In the first pass, we save
* all devices identified as Pre ESR. In the second pass, we save devices
* marked as post ESR.
*
* @param[in] DeviceList Beginning of the device list to save.
* @param[in] Storage Beginning of the context buffer.
* @param[in] CallPoint Indicates whether this is AMD_INIT_RESUME or
* AMD_S3LATE_RESTORE.
* @param[out] ActualBufferSize Actual size used in saving the device list.
* @param[in] StdHeader AMD standard header config param.
*
*/
VOID
SaveDeviceListContext (
IN DEVICE_BLOCK_HEADER *DeviceList,
IN VOID *Storage,
IN CALL_POINTS CallPoint,
OUT UINT32 *ActualBufferSize,
IN AMD_CONFIG_PARAMS *StdHeader
)
{
// Copy device list over
LibAmdMemCopy (Storage,
DeviceList,
(UINTN) DeviceList->RelativeOrMaskOffset,
StdHeader);
SaveDeviceContext (Storage, CallPoint, ActualBufferSize, StdHeader);
}
/*---------------------------------------------------------------------------------------*/
/**
* Saves all devices in the given device list.
*
* This traverses the entire device list twice. In the first pass, we save
* all devices identified as Pre ESR. In the second pass, we save devices
* marked as post ESR.
*
* @param[in,out] DeviceList Beginning of the device list to save.
* @param[in] CallPoint Indicates whether this is AMD_INIT_RESUME or
* AMD_S3LATE_RESTORE.
* @param[out] ActualBufferSize Actual size used in saving the device list.
* @param[in] StdHeader AMD standard header config param.
*
*/
VOID
SaveDeviceContext (
IN DEVICE_BLOCK_HEADER *DeviceList,
IN CALL_POINTS CallPoint,
OUT UINT32 *ActualBufferSize,
IN AMD_CONFIG_PARAMS *StdHeader
)
{
DEVICE_DESCRIPTORS Device;
UINT16 i;
VOID *StartAddress;
VOID *EndAddress;
VOID *OrMask;
StartAddress = DeviceList;
Device.CommonDeviceHeader = (DEVICE_DESCRIPTOR *) &DeviceList[1];
OrMask = (UINT8 *) DeviceList + DeviceList->RelativeOrMaskOffset;
// Process Pre ESR List
for (i = 0; i < DeviceList->NumDevices; i++) {
switch (Device.CommonDeviceHeader->Type) {
case DEV_TYPE_PCI_PRE_ESR:
SavePciDevice (StdHeader, Device.PciDevice, CallPoint, &OrMask);
// Fall through to advance the pointer after saving context
case DEV_TYPE_PCI:
Device.PciDevice++;
break;
case DEV_TYPE_CPCI_PRE_ESR:
SaveConditionalPciDevice (StdHeader, Device.CPciDevice, CallPoint, &OrMask);
// Fall through to advance the pointer after saving context
case DEV_TYPE_CPCI:
Device.CPciDevice++;
break;
case DEV_TYPE_MSR_PRE_ESR:
SaveMsrDevice (StdHeader, Device.MsrDevice, CallPoint, (UINT64 **) &OrMask);
// Fall through to advance the pointer after saving context
case DEV_TYPE_MSR:
Device.MsrDevice++;
break;
case DEV_TYPE_CMSR_PRE_ESR:
SaveConditionalMsrDevice (StdHeader, Device.CMsrDevice, CallPoint, (UINT64 **) &OrMask);
// Fall through to advance the pointer after saving context
case DEV_TYPE_CMSR:
Device.CMsrDevice++;
break;
}
}
Device.CommonDeviceHeader = (DEVICE_DESCRIPTOR *) &DeviceList[1];
// Process Post ESR List
for (i = 0; i < DeviceList->NumDevices; i++) {
switch (Device.CommonDeviceHeader->Type) {
case DEV_TYPE_PCI:
SavePciDevice (StdHeader, Device.PciDevice, CallPoint, &OrMask);
// Fall through to advance the pointer after saving context
case DEV_TYPE_PCI_PRE_ESR:
Device.PciDevice++;
break;
case DEV_TYPE_CPCI:
SaveConditionalPciDevice (StdHeader, Device.CPciDevice, CallPoint, &OrMask);
// Fall through to advance the pointer after saving context
case DEV_TYPE_CPCI_PRE_ESR:
Device.CPciDevice++;
break;
case DEV_TYPE_MSR:
SaveMsrDevice (StdHeader, Device.MsrDevice, CallPoint, (UINT64 **) &OrMask);
// Fall through to advance the pointer after saving context
case DEV_TYPE_MSR_PRE_ESR:
Device.MsrDevice++;
break;
case DEV_TYPE_CMSR:
SaveConditionalMsrDevice (StdHeader, Device.CMsrDevice, CallPoint, (UINT64 **) &OrMask);
// Fall through to advance the pointer after saving context
case DEV_TYPE_CMSR_PRE_ESR:
Device.CMsrDevice++;
break;
}
}
EndAddress = (VOID *) OrMask;
*ActualBufferSize = (UINT32) (EndAddress - StartAddress);
}
/*---------------------------------------------------------------------------------------*/
/**
* Saves the context of a PCI device.
*
* This traverses the provided register list saving PCI registers.
*
* @param[in] StdHeader AMD standard header config param.
* @param[in] Device PCI device to restore.
* @param[in] CallPoint Indicates whether this is AMD_INIT_RESUME or
* AMD_S3LATE_RESTORE.
* @param[in,out] OrMask Current buffer pointer of raw register values.
*
*/
VOID
SavePciDevice (
IN AMD_CONFIG_PARAMS *StdHeader,
IN PCI_DEVICE_DESCRIPTOR *Device,
IN CALL_POINTS CallPoint,
IN OUT VOID **OrMask
)
{
UINT8 RegSizeInBytes;
UINT8 SpecialCaseIndex;
UINT8 *IntermediatePtr;
UINT16 i;
UINT32 Socket;
UINT32 Module;
UINT32 AndMask;
ACCESS_WIDTH AccessWidth;
AGESA_STATUS IgnoredSts;
PCI_ADDR PciAddress;
PCI_REGISTER_BLOCK_HEADER *RegisterHdr;
GetSocketModuleOfNode ((UINT32) Device->Node,
&Socket,
&Module,
StdHeader);
GetPciAddress (StdHeader, Socket, Module, &PciAddress, &IgnoredSts);
if (CallPoint == INIT_RESUME) {
MemFS3GetPciDeviceRegisterList (Device, &RegisterHdr, StdHeader);
} else {
S3GetPciDeviceRegisterList (Device, &RegisterHdr, StdHeader);
}
for (i = 0; i < RegisterHdr->NumRegisters; i++) {
PciAddress.Address.Function = RegisterHdr->RegisterList[i].Function;
PciAddress.Address.Register = RegisterHdr->RegisterList[i].Offset;
RegSizeInBytes = RegisterHdr->RegisterList[i].Type.RegisterSize;
switch (RegSizeInBytes) {
case 1:
AndMask = 0xFFFFFFFF & ((UINT8) RegisterHdr->RegisterList[i].AndMask);
AccessWidth = AccessS3SaveWidth8;
break;
case 2:
AndMask = 0xFFFFFFFF & ((UINT16) RegisterHdr->RegisterList[i].AndMask);
AccessWidth = AccessS3SaveWidth16;
break;
case 3:
// In this case, we don't need to save a register. We just need to call a special
// function to do certain things in the save and resume sequence.
// This should not be used in a non-special case.
AndMask = 0;
RegSizeInBytes = 0;
AccessWidth = 0;
break;
default:
AndMask = RegisterHdr->RegisterList[i].AndMask;
RegSizeInBytes = 4;
AccessWidth = AccessS3SaveWidth32;
break;
}
if (RegisterHdr->RegisterList[i].Type.SpecialCaseFlag == 0) {
ASSERT ((AndMask != 0) && (RegSizeInBytes != 0) && (AccessWidth != 0));
LibAmdPciRead (AccessWidth, PciAddress, *OrMask, StdHeader);
} else {
SpecialCaseIndex = RegisterHdr->RegisterList[i].Type.SpecialCaseIndex;
RegisterHdr->SpecialCases[SpecialCaseIndex].Save (AccessWidth, PciAddress, *OrMask, StdHeader);
}
if (AndMask != 0) {
// If AndMask is 0, then it is a not-care. Don't need to apply it to the OrMask
**((UINT32 **) OrMask) &= AndMask;
}
IntermediatePtr = (UINT8 *) *OrMask;
*OrMask = &IntermediatePtr[RegSizeInBytes]; // += RegSizeInBytes;
}
}
/*---------------------------------------------------------------------------------------*/
/**
* Saves the context of a 'conditional' PCI device.
*
* This traverses the provided register list saving PCI registers when appropriate.
*
* @param[in] StdHeader AMD standard header config param.
* @param[in] Device 'conditional' PCI device to restore.
* @param[in] CallPoint Indicates whether this is AMD_INIT_RESUME or
* AMD_S3LATE_RESTORE.
* @param[in,out] OrMask Current buffer pointer of raw register values.
*
*/
VOID
SaveConditionalPciDevice (
IN AMD_CONFIG_PARAMS *StdHeader,
IN CONDITIONAL_PCI_DEVICE_DESCRIPTOR *Device,
IN CALL_POINTS CallPoint,
IN OUT VOID **OrMask
)
{
UINT8 RegSizeInBytes;
UINT8 SpecialCaseIndex;
UINT8 *IntermediatePtr;
UINT16 i;
UINT32 Socket;
UINT32 Module;
UINT32 AndMask;
ACCESS_WIDTH AccessWidth;
AGESA_STATUS IgnoredSts;
PCI_ADDR PciAddress;
CPCI_REGISTER_BLOCK_HEADER *RegisterHdr;
GetSocketModuleOfNode ((UINT32) Device->Node,
&Socket,
&Module,
StdHeader);
GetPciAddress (StdHeader, Socket, Module, &PciAddress, &IgnoredSts);
if (CallPoint == INIT_RESUME) {
MemFS3GetCPciDeviceRegisterList (Device, &RegisterHdr, StdHeader);
} else {
S3GetCPciDeviceRegisterList (Device, &RegisterHdr, StdHeader);
}
for (i = 0; i < RegisterHdr->NumRegisters; i++) {
if (((Device->Mask1 & RegisterHdr->RegisterList[i].Mask1) != 0) &&
((Device->Mask2 & RegisterHdr->RegisterList[i].Mask2) != 0)) {
PciAddress.Address.Function = RegisterHdr->RegisterList[i].Function;
PciAddress.Address.Register = RegisterHdr->RegisterList[i].Offset;
RegSizeInBytes = RegisterHdr->RegisterList[i].Type.RegisterSize;
switch (RegSizeInBytes) {
case 1:
AndMask = 0xFFFFFFFF & ((UINT8) RegisterHdr->RegisterList[i].AndMask);
AccessWidth = AccessS3SaveWidth8;
break;
case 2:
AndMask = 0xFFFFFFFF & ((UINT16) RegisterHdr->RegisterList[i].AndMask);
AccessWidth = AccessS3SaveWidth16;
break;
case 3:
// In this case, we don't need to save a register. We just need to call a special
// function to do certain things in the save and resume sequence.
// This should not be used in a non-special case.
AndMask = 0;
RegSizeInBytes = 0;
AccessWidth = 0;
break;
default:
AndMask = RegisterHdr->RegisterList[i].AndMask;
RegSizeInBytes = 4;
AccessWidth = AccessS3SaveWidth32;
break;
}
if (RegisterHdr->RegisterList[i].Type.SpecialCaseFlag == 0) {
ASSERT ((AndMask != 0) && (RegSizeInBytes != 0) && (AccessWidth != 0));
LibAmdPciRead (AccessWidth, PciAddress, *OrMask, StdHeader);
} else {
SpecialCaseIndex = RegisterHdr->RegisterList[i].Type.SpecialCaseIndex;
RegisterHdr->SpecialCases[SpecialCaseIndex].Save (AccessWidth, PciAddress, *OrMask, StdHeader);
}
if (AndMask != 0) {
// If AndMask is 0, then it is a not-care. Don't need to apply it to the OrMask
**((UINT32 **) OrMask) &= AndMask;
}
IntermediatePtr = (UINT8 *) *OrMask;
*OrMask = &IntermediatePtr[RegSizeInBytes]; // += RegSizeInBytes;
}
}
}
/*---------------------------------------------------------------------------------------*/
/**
* Saves the context of an MSR device.
*
* This traverses the provided register list saving MSRs.
*
* @param[in] StdHeader AMD standard header config param.
* @param[in] Device MSR device to restore.
* @param[in] CallPoint Indicates whether this is AMD_INIT_RESUME or
* AMD_S3LATE_RESTORE.
* @param[in,out] OrMask Current buffer pointer of raw register values.
*
*/
VOID
SaveMsrDevice (
IN AMD_CONFIG_PARAMS *StdHeader,
IN MSR_DEVICE_DESCRIPTOR *Device,
IN CALL_POINTS CallPoint,
IN OUT UINT64 **OrMask
)
{
UINT8 SpecialCaseIndex;
UINT16 i;
MSR_REGISTER_BLOCK_HEADER *RegisterHdr;
if (CallPoint == INIT_RESUME) {
MemFS3GetMsrDeviceRegisterList (Device, &RegisterHdr, StdHeader);
} else {
S3GetMsrDeviceRegisterList (Device, &RegisterHdr, StdHeader);
}
for (i = 0; i < RegisterHdr->NumRegisters; i++) {
if (RegisterHdr->RegisterList[i].Type.SpecialCaseFlag == 0) {
LibAmdMsrRead (RegisterHdr->RegisterList[i].Address, *OrMask, StdHeader);
} else {
SpecialCaseIndex = RegisterHdr->RegisterList[i].Type.SpecialCaseIndex;
RegisterHdr->SpecialCases[SpecialCaseIndex].Save (RegisterHdr->RegisterList[i].Address, *OrMask, StdHeader);
}
**OrMask &= RegisterHdr->RegisterList[i].AndMask;
(*OrMask)++;
}
}
/*---------------------------------------------------------------------------------------*/
/**
* Saves the context of a 'conditional' MSR device.
*
* This traverses the provided register list saving MSRs when appropriate.
*
* @param[in] StdHeader AMD standard header config param.
* @param[in] Device 'conditional' MSR device to restore.
* @param[in] CallPoint Indicates whether this is AMD_INIT_RESUME or
* AMD_S3LATE_RESTORE.
* @param[in,out] OrMask Current buffer pointer of raw register values.
*
*/
VOID
SaveConditionalMsrDevice (
IN AMD_CONFIG_PARAMS *StdHeader,
IN CONDITIONAL_MSR_DEVICE_DESCRIPTOR *Device,
IN CALL_POINTS CallPoint,
IN OUT UINT64 **OrMask
)
{
UINT8 SpecialCaseIndex;
UINT16 i;
CMSR_REGISTER_BLOCK_HEADER *RegisterHdr;
if (CallPoint == INIT_RESUME) {
MemFS3GetCMsrDeviceRegisterList (Device, &RegisterHdr, StdHeader);
} else {
S3GetCMsrDeviceRegisterList (Device, &RegisterHdr, StdHeader);
}
for (i = 0; i < RegisterHdr->NumRegisters; i++) {
if (((Device->Mask1 & RegisterHdr->RegisterList[i].Mask1) != 0) &&
((Device->Mask2 & RegisterHdr->RegisterList[i].Mask2) != 0)) {
if (RegisterHdr->RegisterList[i].Type.SpecialCaseFlag == 0) {
LibAmdMsrRead (RegisterHdr->RegisterList[i].Address, (UINT64 *) *OrMask, StdHeader);
} else {
SpecialCaseIndex = RegisterHdr->RegisterList[i].Type.SpecialCaseIndex;
RegisterHdr->SpecialCases[SpecialCaseIndex].Save (RegisterHdr->RegisterList[i].Address, (UINT64 *) *OrMask, StdHeader);
}
**OrMask &= RegisterHdr->RegisterList[i].AndMask;
(*OrMask)++;
}
}
}
/*---------------------------------------------------------------------------------------*/
/**
* Determines the maximum amount of space required to store all raw register
* values for the given device list.
*
* This traverses the entire device list, and calculates the worst case size
* of each device in the device list.
*
* @param[in] DeviceList Beginning of the device list.
* @param[in] CallPoint Indicates whether this is AMD_INIT_RESUME or
* AMD_S3LATE_RESTORE.
* @param[in] StdHeader AMD standard header config param.
*
* @retval Size in bytes required for storing all registers.
*/
UINT32
GetWorstCaseContextSize (
IN DEVICE_BLOCK_HEADER *DeviceList,
IN CALL_POINTS CallPoint,
IN AMD_CONFIG_PARAMS *StdHeader
)
{
UINT32 WorstCaseSize;
DEVICE_DESCRIPTORS Device;
UINT16 i;
REGISTER_BLOCK_HEADERS RegisterHdr;
WorstCaseSize = DeviceList->RelativeOrMaskOffset;
Device.CommonDeviceHeader = (DEVICE_DESCRIPTOR *) &DeviceList[1];
// Process Device List
for (i = 0; i < DeviceList->NumDevices; i++) {
switch (Device.CommonDeviceHeader->Type) {
case DEV_TYPE_PCI_PRE_ESR:
// PRE_ESR and post ESR take the same amount of space
case DEV_TYPE_PCI:
if (CallPoint == INIT_RESUME) {
MemFS3GetPciDeviceRegisterList (Device.PciDevice, &RegisterHdr.PciRegisters, StdHeader);
} else {
S3GetPciDeviceRegisterList (Device.PciDevice, &RegisterHdr.PciRegisters, StdHeader);
}
WorstCaseSize += (RegisterHdr.PciRegisters->NumRegisters * 4);
Device.PciDevice++;
break;
case DEV_TYPE_CPCI_PRE_ESR:
// PRE_ESR and post ESR take the same amount of space
case DEV_TYPE_CPCI:
if (CallPoint == INIT_RESUME) {
MemFS3GetCPciDeviceRegisterList (Device.CPciDevice, &RegisterHdr.CPciRegisters, StdHeader);
} else {
S3GetCPciDeviceRegisterList (Device.CPciDevice, &RegisterHdr.CPciRegisters, StdHeader);
}
WorstCaseSize += (RegisterHdr.CPciRegisters->NumRegisters * 4);
Device.CPciDevice++;
break;
case DEV_TYPE_MSR_PRE_ESR:
// PRE_ESR and post ESR take the same amount of space
case DEV_TYPE_MSR:
if (CallPoint == INIT_RESUME) {
MemFS3GetMsrDeviceRegisterList (Device.MsrDevice, &RegisterHdr.MsrRegisters, StdHeader);
} else {
S3GetMsrDeviceRegisterList (Device.MsrDevice, &RegisterHdr.MsrRegisters, StdHeader);
}
WorstCaseSize += (RegisterHdr.MsrRegisters->NumRegisters * 8);
Device.MsrDevice++;
break;
case DEV_TYPE_CMSR_PRE_ESR:
// PRE_ESR and post ESR take the same amount of space
case DEV_TYPE_CMSR:
if (CallPoint == INIT_RESUME) {
MemFS3GetCMsrDeviceRegisterList (Device.CMsrDevice, &RegisterHdr.CMsrRegisters, StdHeader);
} else {
S3GetCMsrDeviceRegisterList (Device.CMsrDevice, &RegisterHdr.CMsrRegisters, StdHeader);
}
WorstCaseSize += (RegisterHdr.CMsrRegisters->NumRegisters * 8);
Device.CMsrDevice++;
break;
default:
ASSERT (FALSE);
}
}
return (WorstCaseSize);
}
/*---------------------------------------------------------------------------------------*/
/**
* Restores all devices marked as 'before exiting self-refresh.'
*
* This traverses the entire device list, restoring all devices identified
* as Pre ESR.
*
* @param[in,out] OrMaskPtr Current buffer pointer of raw register values.
* @param[in] Storage Beginning of the device list.
* @param[in] CallPoint Indicates whether this is AMD_INIT_RESUME or
* AMD_S3LATE_RESTORE.
* @param[in] StdHeader AMD standard header config param.
*
*/
VOID
RestorePreESRContext (
OUT VOID **OrMaskPtr,
IN VOID *Storage,
IN CALL_POINTS CallPoint,
IN AMD_CONFIG_PARAMS *StdHeader
)
{
DEVICE_DESCRIPTORS Device;
UINT16 i;
DEVICE_BLOCK_HEADER *DeviceList;
DeviceList = (DEVICE_BLOCK_HEADER *) Storage;
Device.CommonDeviceHeader = (DEVICE_DESCRIPTOR *) &DeviceList[1];
*OrMaskPtr = (UINT8 *) DeviceList + DeviceList->RelativeOrMaskOffset;
// Process Pre ESR List
for (i = 0; i < DeviceList->NumDevices; i++) {
switch (Device.CommonDeviceHeader->Type) {
case DEV_TYPE_PCI_PRE_ESR:
RestorePciDevice (StdHeader, Device.PciDevice, CallPoint, OrMaskPtr);
// Fall through to advance the pointer after restoring context
case DEV_TYPE_PCI:
Device.PciDevice++;
break;
case DEV_TYPE_CPCI_PRE_ESR:
RestoreConditionalPciDevice (StdHeader, Device.CPciDevice, CallPoint, OrMaskPtr);
// Fall through to advance the pointer after restoring context
case DEV_TYPE_CPCI:
Device.CPciDevice++;
break;
case DEV_TYPE_MSR_PRE_ESR:
RestoreMsrDevice (StdHeader, Device.MsrDevice, CallPoint, (UINT64 **) OrMaskPtr);
// Fall through to advance the pointer after restoring context
case DEV_TYPE_MSR:
Device.MsrDevice++;
break;
case DEV_TYPE_CMSR_PRE_ESR:
RestoreConditionalMsrDevice (StdHeader, Device.CMsrDevice, CallPoint, (UINT64 **) OrMaskPtr);
// Fall through to advance the pointer after restoring context
case DEV_TYPE_CMSR:
Device.CMsrDevice++;
break;
}
}
}
/*---------------------------------------------------------------------------------------*/
/**
* Restores all devices marked as 'after exiting self-refresh.'
*
* This traverses the entire device list, restoring all devices identified
* as Post ESR.
*
* @param[in] OrMaskPtr Current buffer pointer of raw register values.
* @param[in] Storage Beginning of the device list.
* @param[in] CallPoint Indicates whether this is AMD_INIT_RESUME or
* AMD_S3LATE_RESTORE.
* @param[in] StdHeader AMD standard header config param.
*
*/
VOID
RestorePostESRContext (
IN VOID *OrMaskPtr,
IN VOID *Storage,
IN CALL_POINTS CallPoint,
IN AMD_CONFIG_PARAMS *StdHeader
)
{
DEVICE_DESCRIPTORS Device;
UINT16 i;
DEVICE_BLOCK_HEADER *DeviceList;
DeviceList = (DEVICE_BLOCK_HEADER *) Storage;
Device.CommonDeviceHeader = (DEVICE_DESCRIPTOR *) &DeviceList[1];
// Process Pre ESR List
for (i = 0; i < DeviceList->NumDevices; i++) {
switch (Device.CommonDeviceHeader->Type) {
case DEV_TYPE_PCI:
RestorePciDevice (StdHeader, Device.PciDevice, CallPoint, &OrMaskPtr);
// Fall through to advance the pointer after restoring context
case DEV_TYPE_PCI_PRE_ESR:
Device.PciDevice++;
break;
case DEV_TYPE_CPCI:
RestoreConditionalPciDevice (StdHeader, Device.CPciDevice, CallPoint, &OrMaskPtr);
// Fall through to advance the pointer after restoring context
case DEV_TYPE_CPCI_PRE_ESR:
Device.CPciDevice++;
break;
case DEV_TYPE_MSR:
RestoreMsrDevice (StdHeader, Device.MsrDevice, CallPoint, (UINT64 **) &OrMaskPtr);
// Fall through to advance the pointer after restoring context
case DEV_TYPE_MSR_PRE_ESR:
Device.MsrDevice++;
break;
case DEV_TYPE_CMSR:
RestoreConditionalMsrDevice (StdHeader, Device.CMsrDevice, CallPoint, (UINT64 **) &OrMaskPtr);
// Fall through to advance the pointer after restoring context
case DEV_TYPE_CMSR_PRE_ESR:
Device.CMsrDevice++;
break;
}
}
}
/*---------------------------------------------------------------------------------------*/
/**
* Restores the context of a PCI device.
*
* This traverses the provided register list restoring PCI registers.
*
* @param[in] StdHeader AMD standard header config param.
* @param[in] Device 'conditional' PCI device to restore.
* @param[in] CallPoint Indicates whether this is AMD_INIT_RESUME or
* AMD_S3LATE_RESTORE.
* @param[in,out] OrMask Current buffer pointer of raw register values.
*
*/
VOID
RestorePciDevice (
IN AMD_CONFIG_PARAMS *StdHeader,
IN PCI_DEVICE_DESCRIPTOR *Device,
IN CALL_POINTS CallPoint,
IN OUT VOID **OrMask
)
{
UINT8 RegSizeInBytes;
UINT8 SpecialCaseIndex;
UINT8 *IntermediatePtr;
UINT16 i;
UINT32 Socket;
UINT32 Module;
UINT32 AndMask;
UINT32 RegValueRead;
UINT32 RegValueWrite;
ACCESS_WIDTH AccessWidth;
AGESA_STATUS IgnoredSts;
PCI_ADDR PciAddress;
PCI_REGISTER_BLOCK_HEADER *RegisterHdr;
GetSocketModuleOfNode ((UINT32) Device->Node,
&Socket,
&Module,
StdHeader);
GetPciAddress (StdHeader, Socket, Module, &PciAddress, &IgnoredSts);
if (CallPoint == INIT_RESUME) {
MemFS3GetPciDeviceRegisterList (Device, &RegisterHdr, StdHeader);
} else {
S3GetPciDeviceRegisterList (Device, &RegisterHdr, StdHeader);
}
for (i = 0; i < RegisterHdr->NumRegisters; i++) {
PciAddress.Address.Function = RegisterHdr->RegisterList[i].Function;
PciAddress.Address.Register = RegisterHdr->RegisterList[i].Offset;
RegSizeInBytes = RegisterHdr->RegisterList[i].Type.RegisterSize;
switch (RegSizeInBytes) {
case 1:
AndMask = 0xFFFFFFFF & ((UINT8) RegisterHdr->RegisterList[i].AndMask);
RegValueWrite = **(UINT8 **)OrMask;
AccessWidth = AccessS3SaveWidth8;
break;
case 2:
AndMask = 0xFFFFFFFF & ((UINT16) RegisterHdr->RegisterList[i].AndMask);
RegValueWrite = **(UINT16 **)OrMask;
AccessWidth = AccessS3SaveWidth16;
break;
case 3:
// In this case, we don't need to restore a register. We just need to call a special
// function to do certain things in the save and resume sequence.
// This should not be used in a non-special case.
AndMask = 0;
RegValueWrite = 0;
RegSizeInBytes = 0;
AccessWidth = 0;
break;
default:
AndMask = RegisterHdr->RegisterList[i].AndMask;
RegSizeInBytes = 4;
RegValueWrite = **(UINT32 **)OrMask;
AccessWidth = AccessS3SaveWidth32;
break;
}
if (RegisterHdr->RegisterList[i].Type.SpecialCaseFlag == 0) {
ASSERT ((AndMask != 0) && (RegSizeInBytes != 0) && (AccessWidth != 0));
LibAmdPciRead (AccessWidth, PciAddress, &RegValueRead, StdHeader);
RegValueWrite |= RegValueRead & (~AndMask);
LibAmdPciWrite (AccessWidth, PciAddress, &RegValueWrite, StdHeader);
} else {
SpecialCaseIndex = RegisterHdr->RegisterList[i].Type.SpecialCaseIndex;
if (AndMask != 0) {
RegisterHdr->SpecialCases[SpecialCaseIndex].Save (AccessWidth,
PciAddress,
&RegValueRead,
StdHeader);
RegValueWrite |= RegValueRead & (~AndMask);
}
RegisterHdr->SpecialCases[SpecialCaseIndex].Restore (AccessWidth,
PciAddress,
&RegValueWrite,
StdHeader);
}
IntermediatePtr = (UINT8 *) *OrMask;
*OrMask = &IntermediatePtr[RegSizeInBytes]; // += RegSizeInBytes;
}
}
/*---------------------------------------------------------------------------------------*/
/**
* Restores the context of a 'conditional' PCI device.
*
* This traverses the provided register list restoring PCI registers when appropriate.
*
* @param[in] StdHeader AMD standard header config param.
* @param[in] Device 'conditional' PCI device to restore.
* @param[in] CallPoint Indicates whether this is AMD_INIT_RESUME or
* AMD_S3LATE_RESTORE.
* @param[in,out] OrMask Current buffer pointer of raw register values.
*
*/
VOID
RestoreConditionalPciDevice (
IN AMD_CONFIG_PARAMS *StdHeader,
IN CONDITIONAL_PCI_DEVICE_DESCRIPTOR *Device,
IN CALL_POINTS CallPoint,
IN OUT VOID **OrMask
)
{
UINT8 RegSizeInBytes;
UINT8 SpecialCaseIndex;
UINT8 *IntermediatePtr;
UINT16 i;
UINT32 Socket;
UINT32 Module;
UINT32 RegValueRead;
UINT32 RegValueWrite;
UINT32 AndMask;
ACCESS_WIDTH AccessWidth;
AGESA_STATUS IgnoredSts;
PCI_ADDR PciAddress;
CPCI_REGISTER_BLOCK_HEADER *RegisterHdr;
GetSocketModuleOfNode ((UINT32) Device->Node,
&Socket,
&Module,
StdHeader);
GetPciAddress (StdHeader, Socket, Module, &PciAddress, &IgnoredSts);
if (CallPoint == INIT_RESUME) {
MemFS3GetCPciDeviceRegisterList (Device, &RegisterHdr, StdHeader);
} else {
S3GetCPciDeviceRegisterList (Device, &RegisterHdr, StdHeader);
}
for (i = 0; i < RegisterHdr->NumRegisters; i++) {
if (((Device->Mask1 & RegisterHdr->RegisterList[i].Mask1) != 0) &&
((Device->Mask2 & RegisterHdr->RegisterList[i].Mask2) != 0)) {
PciAddress.Address.Function = RegisterHdr->RegisterList[i].Function;
PciAddress.Address.Register = RegisterHdr->RegisterList[i].Offset;
RegSizeInBytes = RegisterHdr->RegisterList[i].Type.RegisterSize;
switch (RegSizeInBytes) {
case 1:
AndMask = 0xFFFFFFFF & ((UINT8) RegisterHdr->RegisterList[i].AndMask);
RegValueWrite = **(UINT8 **)OrMask;
AccessWidth = AccessS3SaveWidth8;
break;
case 2:
AndMask = 0xFFFFFFFF & ((UINT16) RegisterHdr->RegisterList[i].AndMask);
RegValueWrite = **(UINT16 **)OrMask;
AccessWidth = AccessS3SaveWidth16;
break;
case 3:
// In this case, we don't need to restore a register. We just need to call a special
// function to do certain things in the save and resume sequence.
// This should not be used in a non-special case.
AndMask = 0;
RegValueWrite = 0;
RegSizeInBytes = 0;
AccessWidth = 0;
break;
default:
AndMask = RegisterHdr->RegisterList[i].AndMask;
RegSizeInBytes = 4;
RegValueWrite = **(UINT32 **)OrMask;
AccessWidth = AccessS3SaveWidth32;
break;
}
if (RegisterHdr->RegisterList[i].Type.SpecialCaseFlag == 0) {
LibAmdPciRead (AccessWidth, PciAddress, &RegValueRead, StdHeader);
RegValueWrite |= RegValueRead & (~AndMask);
LibAmdPciWrite (AccessWidth, PciAddress, &RegValueWrite, StdHeader);
} else {
SpecialCaseIndex = RegisterHdr->RegisterList[i].Type.SpecialCaseIndex;
if (AndMask != 0) {
RegisterHdr->SpecialCases[SpecialCaseIndex].Save (AccessWidth,
PciAddress,
&RegValueRead,
StdHeader);
RegValueWrite |= RegValueRead & (~AndMask);
}
RegisterHdr->SpecialCases[SpecialCaseIndex].Restore (AccessWidth,
PciAddress,
&RegValueWrite,
StdHeader);
}
IntermediatePtr = (UINT8 *) *OrMask;
*OrMask = &IntermediatePtr[RegSizeInBytes];
}
}
}
/*---------------------------------------------------------------------------------------*/
/**
* Restores the context of an MSR device.
*
* This traverses the provided register list restoring MSRs.
*
* @param[in] StdHeader AMD standard header config param.
* @param[in] Device MSR device to restore.
* @param[in] CallPoint Indicates whether this is AMD_INIT_RESUME or
* AMD_S3LATE_RESTORE.
* @param[in,out] OrMask Current buffer pointer of raw register values.
*
*/
VOID
RestoreMsrDevice (
IN AMD_CONFIG_PARAMS *StdHeader,
IN MSR_DEVICE_DESCRIPTOR *Device,
IN CALL_POINTS CallPoint,
IN OUT UINT64 **OrMask
)
{
UINT8 SpecialCaseIndex;
UINT16 i;
UINT64 RegValueRead;
UINT64 RegValueWrite;
MSR_REGISTER_BLOCK_HEADER *RegisterHdr;
if (CallPoint == INIT_RESUME) {
MemFS3GetMsrDeviceRegisterList (Device, &RegisterHdr, StdHeader);
} else {
S3GetMsrDeviceRegisterList (Device, &RegisterHdr, StdHeader);
}
for (i = 0; i < RegisterHdr->NumRegisters; i++) {
RegValueWrite = **OrMask;
if (RegisterHdr->RegisterList[i].Type.SpecialCaseFlag == 0) {
LibAmdMsrRead (RegisterHdr->RegisterList[i].Address, &RegValueRead, StdHeader);
RegValueWrite |= RegValueRead & (~RegisterHdr->RegisterList[i].AndMask);
LibAmdMsrWrite (RegisterHdr->RegisterList[i].Address, &RegValueWrite, StdHeader);
} else {
SpecialCaseIndex = RegisterHdr->RegisterList[i].Type.SpecialCaseIndex;
RegisterHdr->SpecialCases[SpecialCaseIndex].Save (RegisterHdr->RegisterList[i].Address,
&RegValueRead,
StdHeader);
RegValueWrite |= RegValueRead & (~RegisterHdr->RegisterList[i].AndMask);
RegisterHdr->SpecialCases[SpecialCaseIndex].Restore (RegisterHdr->RegisterList[i].Address,
&RegValueWrite,
StdHeader);
}
(*OrMask)++;
}
}
/*---------------------------------------------------------------------------------------*/
/**
* Restores the context of a 'conditional' MSR device.
*
* This traverses the provided register list restoring MSRs when appropriate.
*
* @param[in] StdHeader AMD standard header config param.
* @param[in] Device 'conditional' MSR device to restore.
* @param[in] CallPoint Indicates whether this is AMD_INIT_RESUME or
* AMD_S3LATE_RESTORE.
* @param[in,out] OrMask Current buffer pointer of raw register values.
*
*/
VOID
RestoreConditionalMsrDevice (
IN AMD_CONFIG_PARAMS *StdHeader,
IN CONDITIONAL_MSR_DEVICE_DESCRIPTOR *Device,
IN CALL_POINTS CallPoint,
IN OUT UINT64 **OrMask
)
{
UINT8 SpecialCaseIndex;
UINT16 i;
UINT64 RegValueRead;
UINT64 RegValueWrite;
CMSR_REGISTER_BLOCK_HEADER *RegisterHdr;
if (CallPoint == INIT_RESUME) {
MemFS3GetCMsrDeviceRegisterList (Device, &RegisterHdr, StdHeader);
} else {
S3GetCMsrDeviceRegisterList (Device, &RegisterHdr, StdHeader);
}
for (i = 0; i < RegisterHdr->NumRegisters; i++) {
if (((Device->Mask1 & RegisterHdr->RegisterList[i].Mask1) != 0) &&
((Device->Mask2 & RegisterHdr->RegisterList[i].Mask2) != 0)) {
RegValueWrite = **OrMask;
if (RegisterHdr->RegisterList[i].Type.SpecialCaseFlag == 0) {
LibAmdMsrRead (RegisterHdr->RegisterList[i].Address, &RegValueRead, StdHeader);
RegValueWrite |= RegValueRead & (~RegisterHdr->RegisterList[i].AndMask);
LibAmdMsrWrite (RegisterHdr->RegisterList[i].Address, &RegValueWrite, StdHeader);
} else {
SpecialCaseIndex = RegisterHdr->RegisterList[i].Type.SpecialCaseIndex;
RegisterHdr->SpecialCases[SpecialCaseIndex].Save (RegisterHdr->RegisterList[i].Address,
&RegValueRead,
StdHeader);
RegValueWrite |= RegValueRead & (~RegisterHdr->RegisterList[i].AndMask);
RegisterHdr->SpecialCases[SpecialCaseIndex].Restore (RegisterHdr->RegisterList[i].Address,
&RegValueWrite,
StdHeader);
}
(*OrMask)++;
}
}
}
/*---------------------------------------------------------------------------------------*/
/**
* Unique device ID to PCI register list translator.
*
* This translates the given device header in storage to the appropriate list
* of registers in the AGESA image.
*
* @param[out] NonMemoryRelatedDeviceList List of devices to save and restore
* during S3LateRestore.
* @param[in] StdHeader AMD standard header config param.
*
*/
VOID
GetNonMemoryRelatedDeviceList (
OUT DEVICE_BLOCK_HEADER **NonMemoryRelatedDeviceList,
IN AMD_CONFIG_PARAMS *StdHeader
)
{
*NonMemoryRelatedDeviceList = NULL;
}
/*---------------------------------------------------------------------------------------*/
/**
* Unique device ID to PCI register list translator.
*
* This translates the given device header in storage to the appropriate list
* of registers in the AGESA image.
*
* @param[in] Device Device header containing the unique ID.
* @param[out] RegisterHdr Output PCI register list pointer.
* @param[in] StdHeader AMD standard header config param.
*
* @retval AGESA_SUCCESS Always succeeds.
*/
AGESA_STATUS
S3GetPciDeviceRegisterList (
IN PCI_DEVICE_DESCRIPTOR *Device,
OUT PCI_REGISTER_BLOCK_HEADER **RegisterHdr,
IN AMD_CONFIG_PARAMS *StdHeader
)
{
*RegisterHdr = NULL;
return AGESA_SUCCESS;
}
/*---------------------------------------------------------------------------------------*/
/**
* Unique device ID to 'conditional' PCI register list translator.
*
* This translates the given device header in storage to the appropriate list
* of registers in the AGESA image.
*
* @param[in] Device Device header containing the unique ID.
* @param[out] RegisterHdr Output 'conditional' PCI register list pointer.
* @param[in] StdHeader AMD standard header config param.
*
* @retval AGESA_SUCCESS Always succeeds.
*/
AGESA_STATUS
S3GetCPciDeviceRegisterList (
IN CONDITIONAL_PCI_DEVICE_DESCRIPTOR *Device,
OUT CPCI_REGISTER_BLOCK_HEADER **RegisterHdr,
IN AMD_CONFIG_PARAMS *StdHeader
)
{
*RegisterHdr = NULL;
return AGESA_SUCCESS;
}
/*---------------------------------------------------------------------------------------*/
/**
* Unique device ID to MSR register list translator.
*
* This translates the given device header in storage to the appropriate list
* of registers in the AGESA image.
*
* @param[in] Device Device header containing the unique ID.
* @param[out] RegisterHdr Output MSR register list pointer.
* @param[in] StdHeader AMD standard header config param.
*
* @retval AGESA_SUCCESS Always succeeds.
*/
AGESA_STATUS
S3GetMsrDeviceRegisterList (
IN MSR_DEVICE_DESCRIPTOR *Device,
OUT MSR_REGISTER_BLOCK_HEADER **RegisterHdr,
IN AMD_CONFIG_PARAMS *StdHeader
)
{
*RegisterHdr = NULL;
return AGESA_SUCCESS;
}
/*---------------------------------------------------------------------------------------*/
/**
* Unique device ID to 'conditional' MSR register list translator.
*
* This translates the given device header in storage to the appropriate list
* of registers in the AGESA image.
*
* @param[in] Device Device header containing the unique ID.
* @param[out] RegisterHdr Output 'conditional' MSR register list pointer.
* @param[in] StdHeader AMD standard header config param.
*
* @retval AGESA_SUCCESS Always succeeds.
*/
AGESA_STATUS
S3GetCMsrDeviceRegisterList (
IN CONDITIONAL_MSR_DEVICE_DESCRIPTOR *Device,
OUT CMSR_REGISTER_BLOCK_HEADER **RegisterHdr,
IN AMD_CONFIG_PARAMS *StdHeader
)
{
*RegisterHdr = NULL;
return AGESA_SUCCESS;
}
/*---------------------------------------------------------------------------------------*/
/**
* Constructor for the AMD_S3_PARAMS structure.
*
* This routine initializes failsafe values for the AMD_S3_PARAMS structure
* to be used by the AMD_INIT_RESUME, AMD_S3_SAVE, and AMD_S3LATE_RESTORE
* entry points.
*
* @param[in,out] S3Params Required input parameter for the AMD_S3_SAVE,
* AMD_INIT_RESUME, and AMD_S3_SAVE entry points.
*
*/
VOID
AmdS3ParamsInitializer (
OUT AMD_S3_PARAMS *S3Params
)
{
S3Params->Signature = 0x52545341;
S3Params->Version = 0x0000;
S3Params->VolatileStorage = NULL;
S3Params->VolatileStorageSize = 0x00000000;
S3Params->Flags = 0x00000000;
S3Params->NvStorage = NULL;
S3Params->NvStorageSize = 0x00000000;
}