blob: 9ffde28e9b4a5c1124ba27cc0e5363afed60d320 [file] [log] [blame]
/* $NoKeywords:$ */
/**
* @file
*
* mnS3.c
*
* Common Northbridge S3
*
* @xrefitem bom "File Content Label" "Release Content"
* @e project: AGESA
* @e sub-project: (Mem/NB)
* @e \$Revision: 84150 $ @e \$Date: 2012-12-12 15:46:25 -0600 (Wed, 12 Dec 2012) $
*
**/
/*****************************************************************************
*
* Copyright (c) 2008 - 2013, 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.
* ***************************************************************************
*
*/
/*
*----------------------------------------------------------------------------
* MODULES USED
*
*----------------------------------------------------------------------------
*/
#include "AGESA.h"
#include "AdvancedApi.h"
#include "amdlib.h"
#include "Ids.h"
#include "OptionMemory.h"
#include "mport.h"
#include "mm.h"
#include "mn.h"
#include "S3.h"
#include "mfs3.h"
#include "cpuFamilyTranslation.h"
#include "heapManager.h"
#include "Filecode.h"
CODE_GROUP (G3_DXE)
RDATA_GROUP (G3_DXE)
#define FILECODE PROC_MEM_NB_MNS3_FILECODE
/*----------------------------------------------------------------------------
* DEFINITIONS AND MACROS
*
*----------------------------------------------------------------------------
*/
/*----------------------------------------------------------------------------
* TYPEDEFS AND STRUCTURES
*
*----------------------------------------------------------------------------
*/
/*----------------------------------------------------------------------------
* PROTOTYPES OF LOCAL FUNCTIONS
*
*----------------------------------------------------------------------------
*/
VOID
STATIC
MemNS3GetSetBitField (
IN ACCESS_WIDTH AccessWidth,
IN PCI_ADDR Address,
IN BOOLEAN IsSet,
IN OUT VOID *Value,
IN OUT VOID *ConfigPtr
);
UINT16
STATIC
MemNS3GetMemClkFreqUnb (
IN OUT MEM_NB_BLOCK *NBPtr,
IN UINT8 FreqId
);
/*----------------------------------------------------------------------------
* EXPORTED FUNCTIONS
*
*----------------------------------------------------------------------------
*/
/* -----------------------------------------------------------------------------*/
/**
*
*
* This function executes the S3 resume for a node on a UNB
*
* @param[in,out] *S3NBPtr - Pointer to the S3_MEM_NB_BLOCK
* @param[in] NodeID - The Node id of the target die
*
* @return BOOLEAN
* TRUE - This is the correct constructor for the targeted node.
* FALSE - This isn't the correct constructor for the targeted node.
*/
BOOLEAN
MemNS3ResumeUNb (
IN OUT S3_MEM_NB_BLOCK *S3NBPtr,
IN UINT8 NodeID
)
{
UINT8 DCT;
MEM_NB_BLOCK *NBPtr;
MEM_DATA_STRUCT *MemPtr;
NBPtr = S3NBPtr->NBPtr;
MemPtr = NBPtr->MemPtr;
// Errata before S3 resume sequence
// Add a hook here
AGESA_TESTPOINT (TpProcMemBeforeAgesaHookBeforeExitSelfRef, &MemPtr->StdHeader);
if (AgesaHookBeforeExitSelfRefresh (0, MemPtr) == AGESA_SUCCESS) {
}
AGESA_TESTPOINT (TpProcMemAfterAgesaHookBeforeExitSelfRef, &MemPtr->StdHeader);
//Override the NB Pstate if needed
IDS_OPTION_HOOK (IDS_NB_PSTATE_DIDVID, S3NBPtr->NBPtr, &MemPtr->StdHeader);
// Set F2x[1,0]90[ExitSelfRef]
// Wait for F2x[1,0]90[ExitSelfRef]=0
for (DCT = 0; DCT < NBPtr->DctCount; DCT ++) {
MemNSwitchDCTNb (NBPtr, DCT);
if (MemNGetBitFieldNb (NBPtr, BFDisDramInterface) == 0) {
MemNSetBitFieldNb (NBPtr, BFDisDllShutdownSR, 1);
MemNSetBitFieldNb (NBPtr, BFExitSelfRef, 1);
while (MemNGetBitFieldNb (NBPtr, BFExitSelfRef) != 0) {}
if (NBPtr->IsSupported[SetDllShutDown]) {
MemNSetBitFieldNb (NBPtr, BFDisDllShutdownSR, 0);
}
}
}
// Errata After S3 resume sequence
return TRUE;
}
/* -----------------------------------------------------------------------------*/
/**
*
*
* This function reads register bitfield
*
* @param[in] AccessWidth - Access width of the register
* @param[in] Address - address of the CSR register in PCI_ADDR format.
* @param[in, out] *Value - Pointer to the value be read.
* @param[in, out] *ConfigPtr - Pointer to Config handle.
* @return none
*/
VOID
MemNS3GetBitFieldNb (
IN ACCESS_WIDTH AccessWidth,
IN PCI_ADDR Address,
IN OUT VOID *Value,
IN OUT VOID *ConfigPtr
)
{
MemNS3GetSetBitField (AccessWidth, Address, FALSE, Value, ConfigPtr);
}
/* -----------------------------------------------------------------------------*/
/**
*
*
* This function writes register bitfield
*
* @param[in] AccessWidth - Access width of the register
* @param[in] Address - address of the CSR register in PCI_ADDR format.
* @param[in, out] *Value - Pointer to the value to be written.
* @param[in, out] *ConfigPtr - Pointer to Config handle.
* @return none
*/
VOID
MemNS3SetBitFieldNb (
IN ACCESS_WIDTH AccessWidth,
IN PCI_ADDR Address,
IN OUT VOID *Value,
IN OUT VOID *ConfigPtr
)
{
MemNS3GetSetBitField (AccessWidth, Address, TRUE, Value, ConfigPtr);
}
/* -----------------------------------------------------------------------------*/
/**
*
*
* This function restores scrubber base register
*
* @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
* @param[in] Node - The Node id of the target die
*
*/
VOID
MemNS3RestoreScrubNb (
IN OUT MEM_NB_BLOCK *NBPtr,
IN UINT8 Node
)
{
UINT32 ScrubAddrRJ16;
ScrubAddrRJ16 = (MemNGetBitFieldNb (NBPtr, BFDramBaseReg0 + Node) & 0xFFFF0000) >> 8;
ScrubAddrRJ16 |= MemNGetBitFieldNb (NBPtr, BFDramBaseHiReg0 + Node) << 24;
MemNSetBitFieldNb (NBPtr, BFScrubAddrLoReg, ScrubAddrRJ16 << 16);
MemNSetBitFieldNb (NBPtr, BFScrubAddrHiReg, ScrubAddrRJ16 >> 16);
}
/* -----------------------------------------------------------------------------*/
/**
*
*
* This function retores Pre Driver Calibration with pre driver calibration code
* code valid bit set.
*
* @param[in] AccessWidth - Access width of the register.
* @param[in] Address - address in PCI_ADDR format.
* @param[in, out] *Value - Pointer to the value to be written.
* @param[in, out] *ConfigPtr - Pointer to Config handle.
* @return none
*/
VOID
MemNS3SetPreDriverCalUnb (
IN ACCESS_WIDTH AccessWidth,
IN PCI_ADDR Address,
IN OUT VOID *Value,
IN OUT VOID *ConfigPtr
)
{
UINT16 RegValue;
RegValue = 0x8000 | *(UINT16 *) Value;
MemNS3SetBitFieldNb (AccessS3SaveWidth16, Address, &RegValue, ConfigPtr);
}
/* -----------------------------------------------------------------------------*/
/**
*
* This function is used by families that use a separate DctCfgSel bit to
* select the current DCT which will be accessed by function 2.
* NOTE: This function must be called BEFORE the NBPtr->Dct variable is
* updated.
*
* @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
* @param[in] *Dct - Pointer to ID of the target DCT
*
*/
BOOLEAN
MemNS3DctCfgSelectUnb (
IN OUT MEM_NB_BLOCK *NBPtr,
IN VOID *Dct
)
{
// Set the DctCfgSel to new DCT
//
MemNSetBitFieldNb (NBPtr, BFDctCfgSel, *(UINT8*)Dct);
return TRUE;
}
/* -----------------------------------------------------------------------------*/
/**
*
*
* This function write to a register that has one copy for each NB Pstate
*
* @param[in] AccessWidth - Access width of the register
* @param[in] Address - address of the CSR register in PCI_ADDR format.
* @param[in, out] *Value - Pointer to the value be read.
* @param[in, out] *ConfigPtr - Pointer to Config handle.
* @return none
*/
VOID
MemNS3GetNBPStateDepRegUnb (
IN ACCESS_WIDTH AccessWidth,
IN PCI_ADDR Address,
IN OUT VOID *Value,
IN OUT VOID *ConfigPtr
)
{
UINT8 NBPstate;
UINT8 TempValue;
UINT8 Dct;
UINT32 Temp;
Temp = Address.Address.Register;
NBPstate = (UINT8) (Temp >> 10);
Dct = (UINT8) Address.Address.Function;
Temp &= 0x3FF;
// Switch Dct
// Function field contains DCT value
Address.Address.Function = FUNC_1;
Address.Address.Register = 0x10C;
LibAmdPciRead (AccessS3SaveWidth8, Address, &TempValue, ConfigPtr);
TempValue = (TempValue & 0xC8) | ((NBPstate << 4) | Dct);
LibAmdPciWrite (AccessS3SaveWidth8, Address, &TempValue, ConfigPtr);
Address.Address.Function = FUNC_2;
Address.Address.Register = Temp;
LibAmdPciRead (AccessWidth, Address, Value, ConfigPtr);
Address.Address.Function = FUNC_1;
Address.Address.Register = 0x10C;
TempValue = 0;
LibAmdPciWrite (AccessS3SaveWidth8, Address, &TempValue, ConfigPtr);
}
/* -----------------------------------------------------------------------------*/
/**
*
*
* This function write to a register that has one copy for each NB Pstate
*
* @param[in] AccessWidth - Access width of the register
* @param[in] Address - address of the CSR register in PCI_ADDR format.
* @param[in, out] *Value - Pointer to the value be read.
* @param[in, out] *ConfigPtr - Pointer to Config handle.
* @return none
*/
VOID
MemNS3SetNBPStateDepRegUnb (
IN ACCESS_WIDTH AccessWidth,
IN PCI_ADDR Address,
IN OUT VOID *Value,
IN OUT VOID *ConfigPtr
)
{
UINT8 NBPstate;
UINT8 TempValue;
UINT8 Dct;
UINT32 Temp;
Temp = Address.Address.Register;
NBPstate = (UINT8) (Temp >> 10);
Dct = (UINT8) Address.Address.Function;
Temp &= 0x3FF;
// Switch Dct
// Function field contains DCT value
Address.Address.Function = FUNC_1;
Address.Address.Register = 0x10C;
LibAmdPciRead (AccessS3SaveWidth8, Address, &TempValue, ConfigPtr);
TempValue = (TempValue & 0xCE) | ((NBPstate << 4) | Dct);
LibAmdPciWrite (AccessS3SaveWidth8, Address, &TempValue, ConfigPtr);
Address.Address.Function = FUNC_2;
Address.Address.Register = Temp;
LibAmdPciWrite (AccessWidth, Address, Value, ConfigPtr);
Address.Address.Function = FUNC_1;
Address.Address.Register = 0x10C;
TempValue = 0;
LibAmdPciWrite (AccessS3SaveWidth32, Address, &TempValue, ConfigPtr);
}
/* -----------------------------------------------------------------------------*/
/**
*
*
* This function read the value of Function 2 PCI register.
*
* @param[in] AccessWidth - Access width of the register
* @param[in] Address - address of the NB register in PCI_ADDR format.
* @param[in] *Value - Pointer to the value be read.
* @param[in, out] *ConfigPtr - Pointer to Config handle.
* @return none
*/
VOID
MemNS3SaveNBRegisterUnb (
IN ACCESS_WIDTH AccessWidth,
IN PCI_ADDR Address,
IN OUT VOID *Value,
IN OUT VOID *ConfigPtr
)
{
UINT8 TempValue;
UINT8 Dct;
UINT32 Temp;
Temp = Address.Address.Register;
Dct = (UINT8) Address.Address.Function;
// Switch Dct
// Function field contains DCT value
Address.Address.Function = FUNC_1;
Address.Address.Register = 0x10C;
LibAmdPciRead (AccessS3SaveWidth8, Address, &TempValue, ConfigPtr);
TempValue = (TempValue & 0xFE) | Dct;
LibAmdPciWrite (AccessS3SaveWidth8, Address, &TempValue, ConfigPtr);
Address.Address.Register = Temp;
Address.Address.Function = FUNC_2;
LibAmdPciRead (AccessWidth, Address, Value, ConfigPtr);
}
/* -----------------------------------------------------------------------------*/
/**
*
*
* This function set the value of Function 2 PCI register.
*
* @param[in] AccessWidth - Access width of the register
* @param[in] Address - address of the NB register in PCI_ADDR format.
* @param[in] *Value - Pointer to the value be write.
* @param[in, out] *ConfigPtr - Pointer to Config handle.
* @return none
*/
VOID
MemNS3RestoreNBRegisterUnb (
IN ACCESS_WIDTH AccessWidth,
IN PCI_ADDR Address,
IN OUT VOID *Value,
IN OUT VOID *ConfigPtr
)
{
UINT8 TempValue;
UINT8 Dct;
UINT32 Temp;
Temp = Address.Address.Register;
Dct = (UINT8) Address.Address.Function;
// Switch Dct
// Function field contains DCT value
Address.Address.Function = FUNC_1;
Address.Address.Register = 0x10C;
LibAmdPciRead (AccessS3SaveWidth8, Address, &TempValue, ConfigPtr);
TempValue = (TempValue & 0xFE) | Dct;
LibAmdPciWrite (AccessS3SaveWidth8, Address, &TempValue, ConfigPtr);
Address.Address.Register = Temp;
Address.Address.Function = FUNC_2;
LibAmdPciWrite (AccessWidth, Address, Value, ConfigPtr);
}
/* -----------------------------------------------------------------------------*/
/**
*
*
* This function sets MemClkFreqVal bit.
*
* @param[in] AccessWidth - Access width of the register.
* @param[in] Address - address in PCI_ADDR format.
* @param[in, out] *Value - Pointer to the value to be written.
* @param[in, out] *ConfigPtr - Pointer to Config handle.
* @return none
*/
VOID
MemNS3SetMemClkFreqValUnb (
IN ACCESS_WIDTH AccessWidth,
IN PCI_ADDR Address,
IN OUT VOID *Value,
IN OUT VOID *ConfigPtr
)
{
UINT32 TempValue;
// 1. Program MemClkFreqVal = 1
MemNS3SaveNBRegisterUnb (AccessWidth, Address, &TempValue, ConfigPtr);
TempValue |= 0x80;
MemNS3RestoreNBRegisterUnb (AccessWidth, Address, &TempValue, ConfigPtr);
// 2. Wait for FreqChgInPrg = 0
MemNS3SaveNBRegisterUnb (AccessWidth, Address, &TempValue, ConfigPtr);
while ((TempValue & 0x200000) != 0) {
MemNS3SaveNBRegisterUnb (AccessWidth, Address, &TempValue, ConfigPtr);
}
}
/* -----------------------------------------------------------------------------*/
/**
*
*
* This function changes memory Pstate context
*
* @param[in] AccessWidth - Access width of the register.
* @param[in] Address - address in PCI_ADDR format. Target MemPState is in
* Address.Address.Register.
* @param[in, out] *Value - Pointer to the value to be written.
* @param[in, out] *ConfigPtr - Pointer to Config handle.
* @return none
*
* @return TRUE
* ----------------------------------------------------------------------------
*/
VOID
MemNS3ChangeMemPStateContextNb (
IN ACCESS_WIDTH AccessWidth,
IN PCI_ADDR Address,
IN OUT VOID *Value,
IN OUT VOID *ConfigPtr
)
{
MEM_NB_BLOCK *NBPtr;
LOCATE_HEAP_PTR LocateBufferPtr;
S3_MEM_NB_BLOCK *S3NBPtr;
UINT8 Die;
IDS_SKIP_HOOK (IDS_BEFORE_S3_SPECIAL, &Address, ConfigPtr) {
// See which Node should be accessed
Die = (UINT8) (Address.Address.Device - 24);
LocateBufferPtr.BufferHandle = AMD_MEM_S3_NB_HANDLE;
if (HeapLocateBuffer (&LocateBufferPtr, ConfigPtr) == AGESA_SUCCESS) {
S3NBPtr = (S3_MEM_NB_BLOCK *) LocateBufferPtr.BufferPtr;
NBPtr = S3NBPtr[Die].NBPtr;
MemNChangeMemPStateContextNb (NBPtr, Address.Address.Register);
}
}
}
/* -----------------------------------------------------------------------------*/
/**
*
*
* This function forces NBPstate to NBP0
*
* @param[in] AccessWidth - Access width of the register
* @param[in] Address - address of the CSR register in PCI_ADDR format.
* @param[in, out] *Value - Pointer to the value be read or written.
* @param[in, out] *ConfigPtr - Pointer to Config handle.
* @return none
*/
VOID
MemNS3ForceNBP0Unb (
IN ACCESS_WIDTH AccessWidth,
IN PCI_ADDR Address,
IN OUT VOID *Value,
IN OUT VOID *ConfigPtr
)
{
UINT8 NbPstateMaxVal;
CPU_SPECIFIC_SERVICES *FamilySpecificServices;
MEM_NB_BLOCK *NBPtr;
LOCATE_HEAP_PTR LocateBufferPtr;
S3_MEM_NB_BLOCK *S3NBPtr;
BOOLEAN SkipTransToLo;
UINT64 MsrValue;
UINT64 PerfCtrlSave;
UINT64 PerfStsSave;
IDS_SKIP_HOOK (IDS_BEFORE_S3_SPECIAL, &Address, ConfigPtr) {
LocateBufferPtr.BufferHandle = AMD_MEM_S3_NB_HANDLE;
if (HeapLocateBuffer (&LocateBufferPtr, ConfigPtr) == AGESA_SUCCESS) {
S3NBPtr = (S3_MEM_NB_BLOCK *) LocateBufferPtr.BufferPtr;
NBPtr = S3NBPtr[0].NBPtr;
// Find out if Current NBPstate is NBPstateLo or not
// If yes, skip the steps that transition the Pstate to Lo
SkipTransToLo = FALSE;
LibAmdMsrRead (MSR_NB_PERF_CTL3, &PerfCtrlSave, &(NBPtr->MemPtr->StdHeader));
MsrValue = 0x00000006004004E9;
LibAmdMsrRead (MSR_NB_PERF_CTR3, &PerfStsSave, &(NBPtr->MemPtr->StdHeader));
LibAmdMsrWrite (MSR_NB_PERF_CTL3, &MsrValue, &(NBPtr->MemPtr->StdHeader));
MsrValue = 0;
LibAmdMsrWrite (MSR_NB_PERF_CTR3, &MsrValue, &(NBPtr->MemPtr->StdHeader));
LibAmdMsrRead (MSR_NB_PERF_CTR3, &MsrValue, &(NBPtr->MemPtr->StdHeader));
if (MsrValue != 0) {
SkipTransToLo = TRUE;
}
LibAmdMsrWrite (MSR_NB_PERF_CTL3, &PerfCtrlSave, &(NBPtr->MemPtr->StdHeader));
LibAmdMsrWrite (MSR_NB_PERF_CTR3, &PerfStsSave, &(NBPtr->MemPtr->StdHeader));
if (MemNGetBitFieldNb (NBPtr, BFCurNbPstate) != 0) {
NBPtr->NbPsCtlReg = MemNGetBitFieldNb (NBPtr, BFNbPstateCtlReg);
// If current NBPstate is already in NBPstateLo, do not do transition to NBPstateLo.
if (!SkipTransToLo) {
// 2.Program D18F5x170 to transition the NB P-state:
// NbPstateLo = NbPstateMaxVal. (HW requires an intermediate transition to low)
// SwNbPstateLoDis = NbPstateDisOnP0 = NbPstateThreshold = 0.
NbPstateMaxVal = (UINT8) MemNGetBitFieldNb (NBPtr, BFNbPstateMaxVal);
MemNSetBitFieldNb (NBPtr, BFNbPstateLo, NbPstateMaxVal);
MemNSetBitFieldNb (NBPtr, BFNbPstateCtlReg, MemNGetBitFieldNb (NBPtr, BFNbPstateCtlReg) & 0xFFFF91FF);
// 3.Wait for D18F5x174[CurNbPstate] to equal NbPstateLo.
while (MemNGetBitFieldNb (NBPtr, BFCurNbPstate) != NbPstateMaxVal) {}
}
// 4.Program D18F5x170 to force the NB P-state:
// NbPstateHi = target NB P-state.
// SwNbPstateLoDis = 1 (triggers the transition)
MemNSetBitFieldNb (NBPtr, BFNbPstateHi, 0);
MemNSetBitFieldNb (NBPtr, BFSwNbPstateLoDis, 1);
// 5.Wait for D18F5x174[CurNbPstate] to equal the target NB P-state.
while (MemNGetBitFieldNb (NBPtr, BFCurNbPstate) != 0) {}
// Update TSC rate
GetCpuServicesOfCurrentCore ((CONST CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, &NBPtr->MemPtr->StdHeader);
FamilySpecificServices->GetTscRate (FamilySpecificServices, &NBPtr->MemPtr->TscRate, &NBPtr->MemPtr->StdHeader);
}
} else {
ASSERT (FALSE);
}
}
}
/* -----------------------------------------------------------------------------*/
/**
*
*
* This function releases NBPState force
*
* @param[in] AccessWidth - Access width of the register
* @param[in] Address - address of the CSR register in PCI_ADDR format.
* @param[in, out] *Value - Pointer to the value be read or written.
* @param[in, out] *ConfigPtr - Pointer to Config handle.
* @return none
*/
VOID
MemNS3ReleaseNBPSUnb (
IN ACCESS_WIDTH AccessWidth,
IN PCI_ADDR Address,
IN OUT VOID *Value,
IN OUT VOID *ConfigPtr
)
{
MEM_NB_BLOCK *NBPtr;
LOCATE_HEAP_PTR LocateBufferPtr;
S3_MEM_NB_BLOCK *S3NBPtr;
IDS_SKIP_HOOK (IDS_BEFORE_S3_SPECIAL, &Address, ConfigPtr) {
LocateBufferPtr.BufferHandle = AMD_MEM_S3_NB_HANDLE;
if (HeapLocateBuffer (&LocateBufferPtr, ConfigPtr) == AGESA_SUCCESS) {
S3NBPtr = (S3_MEM_NB_BLOCK *) LocateBufferPtr.BufferPtr;
NBPtr = S3NBPtr[0].NBPtr;
if (NBPtr->NbPsCtlReg != 0) {
// 6. Restore the initial D18F5x170[SwNbPstateLoDis, NbPstateDisOnP0] values.
MemNSetBitFieldNb (NBPtr, BFNbPstateCtlReg, (MemNGetBitFieldNb (NBPtr, BFNbPstateCtlReg) & 0xFFFF9FFF) | (NBPtr->NbPsCtlReg & 0x6000));
// 7. Restore the initial D18F5x170[NbPstateThreshold, NbPstateHi] values.
MemNSetBitFieldNb (NBPtr, BFNbPstateCtlReg, (MemNGetBitFieldNb (NBPtr, BFNbPstateCtlReg) & 0xFFFFF13F) | (NBPtr->NbPsCtlReg & 0x0EC0));
// 8. Restore the initial D18F5x170[NbPstateLo] values.
MemNSetBitFieldNb (NBPtr, BFNbPstateLo, (NBPtr->NbPsCtlReg >> 3) & 3);
}
} else {
ASSERT (FALSE);
}
}
}
/* -----------------------------------------------------------------------------*/
/**
*
*
* This function saves hob data into NV Ram.
*
* @param[in] AccessWidth - Access width of the register.
* @param[in] Address - address in PCI_ADDR format.
* @param[in, out] *Value - Pointer to the value to be written.
* @param[in, out] *ConfigPtr - Pointer to Config handle.
* @return none
*/
VOID
MemNSaveHobDataUnb (
IN ACCESS_WIDTH AccessWidth,
IN PCI_ADDR Address,
IN OUT VOID *Value,
IN OUT VOID *ConfigPtr
)
{
MEM_NB_BLOCK *NBPtr;
LOCATE_HEAP_PTR LocateBufferPtr;
S3_MEM_NB_BLOCK *S3NBPtr;
UINT8 Die;
// See which Node should be accessed
Die = (UINT8) (Address.Address.Device - 24);
if (Die == 0) {
// Only do this on first node
LocateBufferPtr.BufferHandle = AMD_MEM_S3_NB_HANDLE;
if (HeapLocateBuffer (&LocateBufferPtr, ConfigPtr) == AGESA_SUCCESS) {
S3NBPtr = (S3_MEM_NB_BLOCK *) LocateBufferPtr.BufferPtr;
NBPtr = S3NBPtr[Die].NBPtr;
// Only save value when RefPtr is not NULL
if (NBPtr->RefPtr != NULL) {
if (Address.Address.Function == S3_UMA_SIZE) {
*(UINT32 *) Value = NBPtr->RefPtr->UmaSize;
} else if (Address.Address.Function == S3_UMA_BASE) {
*(UINT32 *) Value = NBPtr->RefPtr->UmaBase;
} else if (Address.Address.Function == S3_UMA_MODE) {
*(UINT8 *) Value = (UINT8 ) NBPtr->RefPtr->UmaMode;
} else if (Address.Address.Function == S3_SUB_4G_CACHE_TOP) {
*(UINT32 *) Value = NBPtr->RefPtr->Sub4GCacheTop;
} else if (Address.Address.Function == S3_SYSLIMIT) {
*(UINT32 *) Value = NBPtr->RefPtr->SysLimit;
} else if (Address.Address.Function == S3_UMA_ATTRIBUTE) {
LocateBufferPtr.BufferHandle = AMD_UMA_INFO_HANDLE;
if (HeapLocateBuffer (&LocateBufferPtr, ConfigPtr) == AGESA_SUCCESS) {
*(UINT32 *) Value = ((UMA_INFO *) LocateBufferPtr.BufferPtr)->UmaAttributes;
}
} else if (Address.Address.Function == S3_VDDIO) {
*(UINT8 *) Value = (UINT8) NBPtr->RefPtr->DDR3Voltage;
} else {
ASSERT (FALSE);
}
}
} else {
ASSERT (FALSE);
}
}
}
/* -----------------------------------------------------------------------------*/
/**
*
*
* This function gets hob data from NV Ram.
*
* @param[in] AccessWidth - Access width of the register.
* @param[in] Address - address in PCI_ADDR format.
* @param[in, out] *Value - Pointer to the value to be written.
* @param[in, out] *ConfigPtr - Pointer to Config handle.
* @return none
*/
VOID
MemNRestoreHobDataUnb (
IN ACCESS_WIDTH AccessWidth,
IN PCI_ADDR Address,
IN OUT VOID *Value,
IN OUT VOID *ConfigPtr
)
{
MEM_NB_BLOCK *NBPtr;
LOCATE_HEAP_PTR LocateBufferPtr;
ALLOCATE_HEAP_PARAMS AllocHeapParams;
S3_MEM_NB_BLOCK *S3NBPtr;
UINT8 Die;
// See which Node should be accessed
Die = (UINT8) (Address.Address.Device - 24);
if (Die == 0) {
// Only do this on first node
LocateBufferPtr.BufferHandle = AMD_MEM_S3_NB_HANDLE;
if (HeapLocateBuffer (&LocateBufferPtr, ConfigPtr) == AGESA_SUCCESS) {
S3NBPtr = (S3_MEM_NB_BLOCK *) LocateBufferPtr.BufferPtr;
NBPtr = S3NBPtr[Die].NBPtr;
// Only save value when RefPtr is not NULL
if (NBPtr->RefPtr != NULL) {
if (Address.Address.Function == S3_UMA_SIZE) {
NBPtr->RefPtr->UmaSize = *(UINT32 *) Value;
} else if (Address.Address.Function == S3_UMA_BASE) {
NBPtr->RefPtr->UmaBase = *(UINT32 *) Value;
} else if (Address.Address.Function == S3_UMA_MODE) {
NBPtr->RefPtr->UmaMode = (UMA_MODE) (*(UINT8 *) Value);
} else if (Address.Address.Function == S3_SUB_4G_CACHE_TOP) {
NBPtr->RefPtr->Sub4GCacheTop = *(UINT32 *) Value;
} else if (Address.Address.Function == S3_SYSLIMIT) {
NBPtr->RefPtr->SysLimit = *(UINT32 *) Value;
} else if (Address.Address.Function == S3_UMA_ATTRIBUTE) {
// Allocate heap for UMA_INFO
AllocHeapParams.RequestedBufferSize = sizeof (UMA_INFO);
AllocHeapParams.BufferHandle = AMD_UMA_INFO_HANDLE;
AllocHeapParams.Persist = HEAP_SYSTEM_MEM;
if (HeapAllocateBuffer (&AllocHeapParams, ConfigPtr) == AGESA_SUCCESS) {
((UMA_INFO *) AllocHeapParams.BufferPtr)->UmaAttributes = *(UINT32 *) Value;
((UMA_INFO *) AllocHeapParams.BufferPtr)->UmaMode = (UINT8) NBPtr->RefPtr->UmaMode;
((UMA_INFO *) AllocHeapParams.BufferPtr)->UmaBase = (UINT64) ((UINT64) NBPtr->RefPtr->UmaBase << 16);
((UMA_INFO *) AllocHeapParams.BufferPtr)->UmaSize = (NBPtr->RefPtr->UmaSize) << 16;
((UMA_INFO *) AllocHeapParams.BufferPtr)->MemClock = MemNS3GetMemClkFreqUnb (NBPtr, (UINT8) NBPtr->GetBitField (NBPtr, BFMemClkFreq));
}
} else if (Address.Address.Function == S3_VDDIO) {
NBPtr->RefPtr->DDR3Voltage = (DIMM_VOLTAGE) *(UINT8 *) Value;
} else {
ASSERT (FALSE);
}
}
} else {
ASSERT (FALSE);
}
}
}
/* -----------------------------------------------------------------------------*/
/**
*
*
* This function enables and disables the fixed MTRR modify bit.
*
* @param[in] MsrAddress - Target MrsAddress
* @param[in] *Value - Value to be written
* @param[in] *StdHeader - Pointer to standard header
*/
VOID
MemNModdifyMtrrFixDramModEn (
IN UINT32 MsrAddress,
IN UINT64 *Value,
IN VOID *StdHeader
)
{
S_UINT64 SMsr;
if (MsrAddress == 0) {
// turn on modification enable bit for fixed MTRR
LibAmdMsrRead (SYS_CFG, (UINT64 *)&SMsr, StdHeader);
SMsr.lo |= 0x80000;
LibAmdMsrWrite (SYS_CFG, (UINT64 *)&SMsr, StdHeader);
} else {
// turn off modification enable bit for fixed MTRR
LibAmdMsrRead (SYS_CFG, (UINT64 *)&SMsr, StdHeader);
SMsr.lo &= ~0x80000;
LibAmdMsrWrite (SYS_CFG, (UINT64 *)&SMsr, StdHeader);
}
}
/*----------------------------------------------------------------------------
* LOCAL FUNCTIONS
*
*----------------------------------------------------------------------------*/
/* -----------------------------------------------------------------------------*/
/**
*
*
* This function reads and writes register bitfield
*
* @param[in] AccessWidth - Access width of the register
* @param[in] Address - address of the CSR register in PCI_ADDR format.
* @param[in] IsSet - if this is a register read or write
* @param[in, out] *Value - Pointer to the value be read or written.
* @param[in, out] *ConfigPtr - Pointer to Config handle.
* @return none
*/
VOID
STATIC
MemNS3GetSetBitField (
IN ACCESS_WIDTH AccessWidth,
IN PCI_ADDR Address,
IN BOOLEAN IsSet,
IN OUT VOID *Value,
IN OUT VOID *ConfigPtr
)
{
BIT_FIELD_NAME BitField;
MEM_NB_BLOCK *NBPtr;
LOCATE_HEAP_PTR LocateBufferPtr;
S3_MEM_NB_BLOCK *S3NBPtr;
UINT32 RegValue;
UINT8 Die;
RegValue = 0;
// See which Node should be accessed
Die = (UINT8) (Address.Address.Device - 24);
LocateBufferPtr.BufferHandle = AMD_MEM_S3_NB_HANDLE;
if (HeapLocateBuffer (&LocateBufferPtr, ConfigPtr) == AGESA_SUCCESS) {
S3NBPtr = (S3_MEM_NB_BLOCK *) LocateBufferPtr.BufferPtr;
NBPtr = S3NBPtr[Die].NBPtr;
// Function field contains the DCT number
NBPtr->SwitchDCT (NBPtr, (UINT8) Address.Address.Function);
// Get the bitfield name to be accessed
// Register field contains the bitfield name
BitField = (BIT_FIELD_NAME) Address.Address.Register;
if (IsSet) {
switch (AccessWidth) {
case AccessS3SaveWidth8:
RegValue = *(UINT8 *) Value;
break;
case AccessS3SaveWidth16:
RegValue = *(UINT16 *) Value;
break;
case AccessS3SaveWidth32:
RegValue = *(UINT32 *) Value;
break;
default:
ASSERT (FALSE);
}
MemNSetBitFieldNb (NBPtr, BitField, RegValue);
} else {
RegValue = MemNGetBitFieldNb (NBPtr, BitField);
switch (AccessWidth) {
case AccessS3SaveWidth8:
*(UINT8 *) Value = (UINT8) RegValue;
break;
case AccessS3SaveWidth16:
*(UINT16 *) Value = (UINT16) RegValue;
break;
case AccessS3SaveWidth32:
*(UINT32 *) Value = RegValue;
break;
default:
ASSERT (FALSE);
}
}
} else {
ASSERT (FALSE);
}
}
/* -----------------------------------------------------------------------------*/
/**
*
*
* This function converts MemClkFreq Id value to MemClk frequency in MHz
*
* @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
* @param[in] FreqId - FreqId from Register
*
* @return MemClk frequency in MHz
*/
UINT16
STATIC
MemNS3GetMemClkFreqUnb (
IN OUT MEM_NB_BLOCK *NBPtr,
IN UINT8 FreqId
)
{
UINT16 MemClkFreq;
if (FreqId > 2) {
MemClkFreq = (FreqId == 14) ? 667 : (300 + ((FreqId - 3) * 33) + (FreqId - 3) / 3);
} else if (FreqId == 2) {
MemClkFreq = 200;
} else {
MemClkFreq = 50 + (50 * FreqId);
}
return MemClkFreq;
}