diff options
Diffstat (limited to 'ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/MrcSsaServices.c')
-rw-r--r-- | ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/MrcSsaServices.c | 2338 |
1 files changed, 2338 insertions, 0 deletions
diff --git a/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/MrcSsaServices.c b/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/MrcSsaServices.c new file mode 100644 index 0000000..2a74103 --- /dev/null +++ b/ReferenceCode/Chipset/SystemAgent/MemoryInit/Pei/MrcSsaServices.c @@ -0,0 +1,2338 @@ +/** + This file contains an 'Intel Peripheral Driver' and uniquely + identified as "Intel Reference Module" and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement. + +@copyright + Copyright (c) 2012 - 2013 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + +@file + MrcSsaServices.c + +@brief + This file contains the SSA BIOS services PPI. +**/ + +#include "MrcGlobal.h" +#include "MrcDdr3.h" +#include "MrcOemDebugPrint.h" +#include "MrcOemIo.h" +#include "MrcOemMmio.h" +#include "MrcOemPlatform.h" +#include "MrcOemSmbus.h" +#include "MrcSsaServices.h" + +#define MAX_CADB_ENTRIES (16) +#define REUT_CPGC_OFFSET (0x400) +#define EXTRA_INDEX_OFFSET (1) +#define SSA_REVISION_BIOS (('0' << 24) | ('0' << 16) | ('7' << 8) | '5') +#define SSA_REVISION_COMMON (('0' << 24) | ('0' << 16) | ('7' << 8) | '5') +#define SSA_REVISION_MEMORY (('0' << 24) | ('0' << 16) | ('7' << 8) | '5') +#define SPD_SENSOR_BASE_ADDRESS (0x30) +#define SPD_SENSOR_TEMPERATURE_OFFSET (5) + +extern EFI_GUID gSsaBiosServicesPpiGuid; + +typedef union { + struct { + UINT32 Low; + UINT32 High; + } Data32; + UINT64 Data; +} UINT64_STRUCT; + +#ifdef SSA_FLAG + +/** + +@brief + Verify that the indicated socket is present and enabled. + + @param[in] MrcData - Pointer to the MRC global data area. + @param[in] Socket - Zero based CPU socket number. + + @retval TRUE if present and enabled, otherwise FALSE. + +**/ +static +BOOLEAN +IsSocketPresent ( + const MrcParameters * const MrcData, + const UINT8 Socket + ) +{ + return ((Socket < MAX_CPU_SOCKETS) ? TRUE : FALSE); +} + +/** + +@brief + Verify that the indicated controller is present and enabled. + + @param[in] MrcData - Pointer to the MRC global data area. + @param[in] Socket - Zero based CPU socket number. + @param[in] Controller - Zero based memory controller number. + + @retval TRUE if present and enabled, otherwise FALSE. + +**/ +static +BOOLEAN +IsControllerPresent ( + const MrcParameters * const MrcData, + const UINT8 Socket, + const UINT8 Controller + ) +{ + return (((IsSocketPresent (MrcData, Socket)) && + (Controller < MAX_CONTROLLERS) && + (MrcData->SysOut.Outputs.Controller[Controller].Status == CONTROLLER_PRESENT)) ? + TRUE : FALSE); +} + +/** + +@brief + Verify that the indicated channel is present and enabled. + + @param[in] MrcData - Pointer to the MRC global data area. + @param[in] Socket - Zero based CPU socket number. + @param[in] Controller - Zero based memory controller number. + @param[in] Channel - Zero based memory channel number. + + @retval TRUE if present and enabled, otherwise FALSE. + +**/ +static +BOOLEAN +IsChannelPresent ( + const MrcParameters * const MrcData, + const UINT8 Socket, + const UINT8 Controller, + const UINT8 Channel + ) +{ + return (((IsControllerPresent (MrcData, Socket, Controller)) && + (Channel < MAX_CHANNEL) && + (MrcData->SysOut.Outputs.Controller[Controller].Channel[Channel].Status == CHANNEL_PRESENT)) ? + TRUE : FALSE); +} + +/** + +@brief + Verify that the indicated DIMM is present and enabled. + + @param[in] MrcData - Pointer to the MRC global data area. + @param[in] Socket - Zero based CPU socket number. + @param[in] Controller - Zero based memory controller number. + @param[in] Channel - Zero based memory channel number. + @param[in] Dimm - Zero based memory DIMM number. + + @retval TRUE if present and enabled, otherwise FALSE. + +**/ +static +BOOLEAN +IsDimmPresent ( + const MrcParameters * const MrcData, + const UINT8 Socket, + const UINT8 Controller, + const UINT8 Channel, + const UINT8 Dimm + ) +{ + return (((IsChannelPresent (MrcData, Socket, Controller, Channel)) && + (Dimm < MAX_DIMMS_IN_CHANNEL) && + (MrcData->SysOut.Outputs.Controller[Controller].Channel[Channel].Dimm[Dimm].Status == DIMM_PRESENT)) ? + TRUE : FALSE); +} + +/** + +@brief + Verify that the indicated rank is present and enabled. + + @param[in] MrcData - Pointer to the MRC global data area. + @param[in] Socket - Zero based CPU socket number. + @param[in] Controller - Zero based memory controller number. + @param[in] Channel - Zero based memory channel number. + @param[in] Dimm - Zero based memory DIMM number. + @param[in] Rank - Zero based memory rank number in the DIMM. + + @retval TRUE if present and enabled, otherwise FALSE. + +**/ +static +BOOLEAN +IsRankPresent ( + const MrcParameters * const MrcData, + const UINT8 Socket, + const UINT8 Controller, + const UINT8 Channel, + const UINT8 Dimm, + const UINT8 Rank + ) +{ + return (((IsDimmPresent (MrcData, Socket, Controller, Channel, Dimm)) && + (Rank < MAX_RANK_IN_DIMM) && + ((MrcData->SysOut.Outputs.Controller[Controller].Channel[Channel].Dimm[Dimm].RankInDIMM - 1) >= Rank)) ? + TRUE : FALSE); +} + +/** + +@brief + Initialize the heap so that malloc and free can be used. + + @param[in] MrcData - Pointer to the MRC global data area. + + @retval TRUE if present and enabled, otherwise FALSE. + +**/ + +static +BOOLEAN +InitHeap ( + const MrcParameters * const MrcData + ) +{ + const MrcInput *Inputs; + UINT8 *HeapLimitPtr; + HeapBufHeader *HeapBase; + UINT8 *BaseAddr; + + Inputs = &MrcData->SysIn.Inputs; + + // + // If heap is provided + // + if (Inputs->SsaHeapSize) { + BaseAddr = (UINT8 *) Inputs->SsaHeapBase; + HeapLimitPtr = BaseAddr + Inputs->SsaHeapSize; + + // + // Initialize the start header + // + HeapBase = (HeapBufHeader *) BaseAddr; + HeapBase->BufBase = BaseAddr + sizeof (HeapBufHeader); + HeapBase->BufLimit = Inputs->SsaHeapSize - (2 * sizeof (HeapBufHeader)); + HeapBase->BufFlags.Data = 0; + + // + // Initialize the end header + // + HeapBase = (HeapBufHeader *) (HeapLimitPtr - sizeof (HeapBufHeader)); + HeapBase->BufBase = HeapLimitPtr; + HeapBase->BufLimit = 0; + HeapBase->BufFlags.Bits.HeapEnd = 1; + return TRUE; + } + return FALSE; +} + +/** + +@brief + Reads a variable-sized value from a memory mapped register using an absolute address. + This function takes advantage of any caching implemented by BIOS. + + @param[in, out] PeiServices - An indirect pointer to the PEI Services Table published by the PEI Foundation. + @param[in, out] This - Interface pointer that implements the particular SSA_BIOS_SERVICES_PPI instance. + @param[in] Width - The size of the value to write. + @param[in] Address - Address of the register to be accessed. + @param[out] Buffer - Value storage location. + + @retval Nothing. + +**/ +static +VOID +ReadMem ( + EFI_PEI_SERVICES **PeiServices, + SSA_BIOS_SERVICES_PPI *This, + REG_WIDTH Width, + EFI_PHYSICAL_ADDRESS Address, + VOID *Buffer + ) +{ + MMIO_BUFFER *MmioBuffer; + + MmioBuffer = (MMIO_BUFFER *) Buffer; + switch (Width) { + case RegWidth8: + MrcOemMmioRead8 ((U32) Address, &MmioBuffer->Data8, 0); + break; + + case RegWidth16: + MrcOemMmioRead16 ((U32) Address, &MmioBuffer->Data16, 0); + break; + + case RegWidth32: + MrcOemMmioRead ((U32) Address, &MmioBuffer->Data32, 0); + break; + + case RegWidth64: + MrcOemMmioRead64 ((U32) Address, &MmioBuffer->Data64, 0); + break; + + default: + break; + } + return; +} + +/** + +@brief + Writes a variable sized value to a memory mapped register using an absolute address. + + @param[in, out] PeiServices - An indirect pointer to the PEI Services Table published by the PEI Foundation. + @param[in, out] This - Interface pointer that implements the particular SSA_BIOS_SERVICES_PPI instance. + @param[in] Width - The size of the value to write. + @param[in] Address - Address of the register to be accessed. + @param[in] Buffer - Value to write. + + @retval Nothing. + +**/ +static +VOID +WriteMem ( + EFI_PEI_SERVICES **PeiServices, + SSA_BIOS_SERVICES_PPI *This, + REG_WIDTH Width, + EFI_PHYSICAL_ADDRESS Address, + VOID *Buffer + ) +{ + MMIO_BUFFER *MmioBuffer; + + MmioBuffer = (MMIO_BUFFER *) Buffer; + switch (Width) { + case RegWidth8: + MrcOemMmioWrite8 ((U32) Address, MmioBuffer->Data8, 0); + break; + + case RegWidth16: + MrcOemMmioWrite16 ((U32) Address, MmioBuffer->Data16, 0); + break; + + case RegWidth32: + MrcOemMmioWrite ((U32) Address, MmioBuffer->Data32, 0); + break; + + case RegWidth64: + MrcOemMmioWrite64 ((U32) Address, MmioBuffer->Data64, 0); + break; + + default: + break; + } + return; +} + +/** + +@brief + Reads a variable sized value from I/O. + This function takes advantage of any caching implemented by BIOS. + + @param[in, out] PeiServices - An indirect pointer to the PEI Services Table published by the PEI Foundation. + @param[in, out] This - Interface pointer that implements the particular SSA_BIOS_SERVICES_PPI instance. + @param[in] Width - The size of the value to write. + @param[in] Address - Address of the I/O to be accessed. + @param[out] Buffer - Value storage location. + + @retval Nothing. + +**/ +static +VOID +ReadIo ( + EFI_PEI_SERVICES **PeiServices, + SSA_BIOS_SERVICES_PPI *This, + REG_WIDTH Width, + UINT32 Address, + VOID *Buffer + ) +{ + IO_BUFFER *IoBuffer; + + IoBuffer = (IO_BUFFER *) Buffer; + switch (Width) { + case RegWidth8: + IoBuffer->Data8 = MrcOemInPort8 ((UINT16) Address); + break; + + case RegWidth16: + IoBuffer->Data16 = MrcOemInPort16 ((UINT16) Address); + break; + + case RegWidth32: + IoBuffer->Data32 = MrcOemInPort32 ((UINT16) Address); + break; + + default: + break; + } + return; +} + +/** + +@brief + Writes a variable sized value to I/O. + + @param[in, out] PeiServices - An indirect pointer to the PEI Services Table published by the PEI Foundation. + @param[in, out] This - Interface pointer that implements the particular SSA_BIOS_SERVICES_PPI instance. + @param[in] Width - The size of the value to write. + @param[in] Address - Address of the I/O to be accessed. + @param[in] Buffer - Value to write. + + @retval Nothing. + +**/ +static +VOID +WriteIo ( + EFI_PEI_SERVICES **PeiServices, + SSA_BIOS_SERVICES_PPI *This, + REG_WIDTH Width, + UINT32 Address, + VOID *Buffer + ) +{ + IO_BUFFER *IoBuffer; + + IoBuffer = (IO_BUFFER *) Buffer; + switch (Width) { + case RegWidth8: + MrcOemOutPort8 ((UINT16) Address, IoBuffer->Data8); + break; + + case RegWidth16: + MrcOemOutPort16 ((UINT16) Address, IoBuffer->Data16); + break; + + case RegWidth32: + MrcOemOutPort32 ((UINT16) Address, IoBuffer->Data32); + break; + + default: + break; + } + return; +} + +/** + +@brief + Reads a variable sized value from the PCI config space register. + This function takes advantage of any caching implemented by BIOS. + + @param[in, out] PeiServices - An indirect pointer to the PEI Services Table published by the PEI Foundation. + @param[in, out] This - Interface pointer that implements the particular SSA_BIOS_SERVICES_PPI instance. + @param[in] Width - The size of the value to write. + @param[in] Address - Address of the I/O to be accessed. Must be modulo 'Width'. + @param[out] Buffer - Value storage location. + @param[in] CachedData - If set to TRUE, returns the Cached data (if applicable) for performance. If set to FALSE returns the data read from device. + + @retval Nothing. + +**/ +static +VOID +ReadPci ( + EFI_PEI_SERVICES **PeiServices, + SSA_BIOS_SERVICES_PPI *This, + REG_WIDTH Width, + EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS *Address, + VOID *Buffer, + BOOLEAN CachedData + ) +{ + PCI_BUFFER *PciBuffer; + PCI_CONFIG_SPACE PciAddress; + UINT32 Value; + + PciBuffer = (PCI_BUFFER *) Buffer; + PciAddress.Value = 0; + PciAddress.Bits.Bus = Address->Bus; + PciAddress.Bits.Device = Address->Device; + PciAddress.Bits.Function = Address->Function; + PciAddress.Bits.Offset = Address->Register; + PciAddress.Bits.Enable = 1; + MrcOemOutPort32 (MrcOemPciIndex (), PciAddress.Value); + Value = MrcOemInPort32 (MrcOemPciData ()); + + switch (Width) { + case RegWidth8: + PciBuffer->Data8 = (UINT8) Value; + break; + + case RegWidth16: + PciBuffer->Data16 = (UINT16) Value; + break; + + case RegWidth32: + PciBuffer->Data32 = Value; + break; + + default: + break; + } + + return; +} + +/** + +@brief + Writes a variable sized value to the PCI config space register. + + @param[in, out] PeiServices - An indirect pointer to the PEI Services Table published by the PEI Foundation. + @param[in, out] This - Interface pointer that implements the particular SSA_BIOS_SERVICES_PPI instance. + @param[in] Width - The size of the value to write. + @param[in] Address - Address of the I/O to be accessed. Must be modulo 'Width'. + @param[in] Buffer - Value to write. + @param[in] CachedData - If set to TRUE, returns the Cached data (if applicable) for performance. If set to FALSE returns the data read from device. + + @retval Nothing. + +**/ +static +VOID +WritePci ( + EFI_PEI_SERVICES **PeiServices, + SSA_BIOS_SERVICES_PPI *This, + REG_WIDTH Width, + EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS *Address, + VOID *Buffer, + BOOLEAN CachedData + ) +{ + PCI_BUFFER *PciBuffer; + PCI_CONFIG_SPACE PciAddress; + BOOLEAN DoIt; + UINT32 Value; + + PciBuffer = (PCI_BUFFER *) Buffer; + DoIt = TRUE; + PciAddress.Value = 0; + PciAddress.Bits.Bus = Address->Bus; + PciAddress.Bits.Device = Address->Device; + PciAddress.Bits.Function = Address->Function; + PciAddress.Bits.Offset = Address->Register; + PciAddress.Bits.Enable = 1; + Value = 0; + + switch (Width) { + case RegWidth8: + ReadPci (PeiServices, This, RegWidth32, Address, (PCI_BUFFER *) &Value, FALSE); + Value &= ~0xFF; + Value |= PciBuffer->Data8; + break; + + case RegWidth16: + ReadPci (PeiServices, This, RegWidth32, Address, (PCI_BUFFER *) &Value, FALSE); + Value &= ~0xFFFF; + Value |= PciBuffer->Data16; + break; + + case RegWidth32: + Value = PciBuffer->Data32; + break; + + default: + Value = 0; + DoIt = FALSE; + break; + } + + if (DoIt) { + MrcOemOutPort32 (MrcOemPciIndex (), PciAddress.Value); + MrcOemOutPort32 (MrcOemPciData (), Value); + } + + return; +} + +/** + +@brief + Gets a base address to be used in the different memory map or MMIO register access functions. + + @param[in, out] PeiServices - An indirect pointer to the PEI Services Table published by the PEI Foundation. + @param[in, out] This - Interface pointer that implements the particular SSA_BIOS_SERVICES_PPI instance. + @param[in] Socket - Zero based CPU socket number. + @param[in] Controller - Zero based controller number. + @param[in] Index - Additional index to locate the register. + @param[in] BaseAddressType - Value that indicates the type of base address to be retrieved. + @param[in] BaseAddress - Where to write the base address + + @retval Success or error code. + +**/ +static +SSA_STATUS +GetBaseAddress ( + EFI_PEI_SERVICES **PeiServices, + SSA_BIOS_SERVICES_PPI *This, + UINT8 Socket, + UINT8 Controller, + UINT8 Index, + BASE_ADDR_TYPE BaseAddressType, + EFI_PHYSICAL_ADDRESS *BaseAddress + ) +{ + MrcParameters *MrcData; + + MrcData = (MrcParameters *) This->SsaMemoryConfig.MrcData; + switch (BaseAddressType) { + case MCH_BAR: + *BaseAddress = IsControllerPresent (MrcData, Socket, Controller) ? + MrcData->SysIn.Inputs.MchBarBaseAddress : 0; + return (Success); + default: + break; + } + return (UnsupportedValue); +} + +/** + +@brief + Function used to dynamically allocate memory. + + @param[in, out] PeiServices - An indirect pointer to the PEI Services Table published by the PEI Foundation. + @param[in, out] This - Interface pointer that implements the particular SSA_BIOS_SERVICES_PPI instance. + @param[in] Size - Amount of memory in bytes to allocate. + + @retval Returns a pointer to an allocated memory block on success or NULL on failure. + +**/ +static +VOID * +Malloc ( + EFI_PEI_SERVICES **PeiServices, + SSA_BIOS_SERVICES_PPI *This, + UINT32 Size + ) +{ + MrcInput *Inputs; + MrcDebug *Debug; + HeapBufHeader *HeaderPtr; + HeapBufHeader *NextHeaderPtr; + MrcParameters *MrcData; + + MrcData = (MrcParameters *) This->SsaMemoryConfig.MrcData; + Inputs = &MrcData->SysIn.Inputs; + Debug = &Inputs->Debug; + + if ((Size == 0) || (Inputs->SsaHeapSize == 0)) { + return NULL; + } + + if (Inputs->SsaHeapFlag.Bits.Init == 0) { + Inputs->Debug.Current = 0; + Inputs->SsaHeapFlag.Bits.Init = 1; + InitHeap (MrcData); + } + + // + // Round size up to a QWORD integral. + // + Size += sizeof (UINT64) - (Size % sizeof (UINT64)); + + // + // Check to see if request exceeds available heap size. + // + if (Size > (Inputs->SsaHeapSize - (3 * sizeof (HeapBufHeader)))) { + return NULL; + } + + HeaderPtr = (HeapBufHeader *) Inputs->SsaHeapBase; + + // + // Walk the heap looking for an available buffer. + // + while ((HeaderPtr->BufFlags.Bits.Occupied > 0) || (HeaderPtr->BufLimit < Size)) { + HeaderPtr = (HeapBufHeader *) (HeaderPtr->BufBase + HeaderPtr->BufLimit); + } + + // + // Check for the end of heap space. + // + if (HeaderPtr->BufFlags.Bits.HeapEnd > 0) { + return NULL; + } + + // + // Lock memory for the buffer. + // + HeaderPtr->BufFlags.Bits.Occupied = 1; + + // + // Initialize the current size and next header if required. + // + if ((HeaderPtr->BufLimit - Size) > sizeof (HeapBufHeader)) { + NextHeaderPtr = (HeapBufHeader *) (HeaderPtr->BufBase + Size); + NextHeaderPtr->BufBase = (UINT8 *) NextHeaderPtr + sizeof (HeapBufHeader); + NextHeaderPtr->BufLimit = HeaderPtr->BufLimit - Size - sizeof (HeapBufHeader); + NextHeaderPtr->BufFlags.Data = 0; + HeaderPtr->BufLimit = Size; + } + + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "SSA malloc. Base = %Xh, Size = %u\n", HeaderPtr->BufBase, Size); + // + // Return the current base. + // + return HeaderPtr->BufBase; +} + +/** + +@brief + Function used to release memory allocated using Malloc. + + @param[in, out] PeiServices - An indirect pointer to the PEI Services Table published by the PEI Foundation. + @param[in, out] This - Interface pointer that implements the particular SSA_BIOS_SERVICES_PPI instance. + @param[in] Buffer - The buffer to return to the free pool. + + @retval Nothing. + +**/ +static +VOID +Free ( + EFI_PEI_SERVICES **PeiServices, + SSA_BIOS_SERVICES_PPI *This, + VOID *Buffer + ) +{ + const MrcInput *Inputs; + const MrcDebug *Debug; + HeapBufHeader *HeaderPtr; + HeapBufHeader *TempPtr; + MrcParameters *MrcData; + + MrcData = (MrcParameters *) This->SsaMemoryConfig.MrcData; + Inputs = &MrcData->SysIn.Inputs; + Debug = &Inputs->Debug; + if (Inputs->SsaHeapSize > 0) { + // + // Initialize a pointer to the given buffer header. + // + HeaderPtr = (HeapBufHeader *) ((UINT8 *) Buffer - sizeof (HeapBufHeader)); + + // + // Validate the given pointer before proceeding. + // + if (HeaderPtr->BufBase == Buffer) { + // + // Free the given buffer. + // + HeaderPtr->BufFlags.Bits.Occupied = 0; + + // + // Initialize the root header. + // + HeaderPtr = (HeapBufHeader *) Inputs->SsaHeapBase; + + // + // Walk the heap looking for holes to merge. + // + do { + // + // Find the next hole. + // + while (HeaderPtr->BufFlags.Bits.Occupied > 0) { + HeaderPtr = (HeapBufHeader *) (HeaderPtr->BufBase + HeaderPtr->BufLimit); + } + + // + // Check for the end of heap space. + // + if (HeaderPtr->BufFlags.Bits.HeapEnd > 0) { + break; + } + + // + // Look for adjacent holes to merge. + // + TempPtr = (HeapBufHeader *) (HeaderPtr->BufBase + HeaderPtr->BufLimit); + while ((TempPtr->BufFlags.Bits.Occupied == 0) && (TempPtr->BufFlags.Bits.HeapEnd == 0)) { + // + // Add this buffer to the current limit and move to the next buffer. + // + HeaderPtr->BufLimit += TempPtr->BufLimit + sizeof (HeapBufHeader); + TempPtr = (HeapBufHeader *) (TempPtr->BufBase + TempPtr->BufLimit); + } + // + // Move to the next buffer. + // + HeaderPtr = (HeapBufHeader *) (HeaderPtr->BufBase + HeaderPtr->BufLimit); + + } while (HeaderPtr->BufFlags.Bits.HeapEnd == 0); + MRC_DEBUG_MSG (Debug, MSG_LEVEL_NOTE, "SSA free. Base = %Xh\n", Buffer); + } + } + return; +} + +/** + +@brief + Function used to output debug messages to the output logging device. + + @param[in, out] PeiServices - An indirect pointer to the PEI Services Table published by the PEI Foundation. + @param[in, out] This - Interface pointer that implements the particular SSA_BIOS_SERVICES_PPI instance. + @param[in] PrintLevel - The severity level of the string. + @param[in] FormatString - The reduced set of printf style format specifiers. + %[flags][width]type + [flags] '-' left align + [flags] '+' prefix with sign (+ or -) + [flags] '0' zero pad numbers + [flags] ' ' prefix black in front of postive numbers + [width] non negative decimal integer that specifies the width to print a value. + [width] '*' get the width from a int argument on the stack. + type 'd'|'i' signed decimal integer + type 'u' unsigned integer + type 'x'|'X' hexidecimal using "ABCDEF" + type 'c' print character + type 'p' print a pointer to void + type 's' print a null terminated string + @param[in] ... - Variable list of output values. + + @retval Nothing. + +**/ +static +VOID +SsaDebugPrint ( + EFI_PEI_SERVICES **PeiServices, + SSA_BIOS_SERVICES_PPI *This, + PRINT_LEVEL PrintLevel, + UINT8 *FormatString, + ... + ) +{ +#ifdef MRC_DEBUG_PRINT + MrcVaList Marker; + char Buffer[MAX_STRING_LENGTH]; + + if (FormatString != NULL) { + VA_START (Marker, FormatString); + if (StringFormatter (FormatString, Marker, sizeof (Buffer), Buffer) > 0) { + DEBUG ((PrintLevel, Buffer)); + } + } +#endif + + return; +} + +/** + +@brief + Returns the platform's memory voltage (VDD). + + @param[in, out] PeiServices - An indirect pointer to the PEI Services Table published by the PEI Foundation. + @param[in, out] This - Interface pointer that implements the particular SSA_BIOS_SERVICES_PPI instance. + @param[out] Voltage - Where the platform's memory voltage (in mV) will be written. + + @retval Success or failure code. + +**/ +static +SSA_STATUS +GetMemVoltage ( + EFI_PEI_SERVICES **PeiServices, + SSA_BIOS_SERVICES_PPI *This, + UINT32 *Voltage + ) +{ + MrcParameters *MrcData; + + MrcData = (MrcParameters *) This->SsaMemoryConfig.MrcData; + *Voltage = MrcData->SysOut.Outputs.VddVoltage[MrcData->SysIn.Inputs.MemoryProfile]; + return (Success); +} + +/** + +@brief + Sets the platform's memory voltage (VDD). + + @param[in, out] PeiServices - An indirect pointer to the PEI Services Table published by the PEI Foundation. + @param[in, out] This - Interface pointer that implements the particular SSA_BIOS_SERVICES_PPI instance. + @param[in] Voltage - The requested platform's memory voltage (in mV). + + @retval Success or failure code. + +**/ +static +SSA_STATUS +SetMemVoltage ( + EFI_PEI_SERVICES **PeiServices, + SSA_BIOS_SERVICES_PPI *This, + UINT32 *Voltage + ) +{ + UINT32 VddSettleWaitTime; + MrcParameters *MrcData; + + MrcData = (MrcParameters *) This->SsaMemoryConfig.MrcData; + VddSettleWaitTime = MIN (MrcData->SysIn.Inputs.VddSettleWaitTime, 200); + MrcOemVDDVoltageCheckAndSwitch (MrcData, *Voltage, &VddSettleWaitTime); + MrcWait (MrcData, VddSettleWaitTime * HPET_1US); + MrcData->SysOut.Outputs.VddVoltage[MrcData->SysIn.Inputs.MemoryProfile] = *Voltage; + return (Success); +} + +/** + +@brief + Returns the temperature of the specified DIMM in whole degree Celsius. + + @param[in, out] PeiServices - An indirect pointer to the PEI Services Table published by the PEI Foundation. + @param[in, out] This - Interface pointer that implements the particular SSA_BIOS_SERVICES_PPI instance. + @param[in] Socket - Zero based CPU socket number. + @param[in] Controller - Zero based controller number. + @param[in] Channel - Zero based channel number. + @param[in] Dimm - Zero based DIMM number. + @param[out] Temperature - Where the DIMM's temperature in whole degree Celsius will be written. + + @retval Success or failure code. + +**/ +static +SSA_STATUS +GetMemTemp ( + EFI_PEI_SERVICES **PeiServices, + SSA_BIOS_SERVICES_PPI *This, + UINT8 Socket, + UINT8 Controller, + UINT8 Channel, + UINT8 Dimm, + INT32 *Temperature + ) +{ + const MrcParameters *MrcData; + const MrcInput *Inputs; + UINT16 Value; + UINT8 Address; + union { + struct { + UINT16 Fraction : 4; + UINT16 Whole : 8; + UINT16 Sign : 1; + UINT16 Low : 1; + UINT16 High : 1; + UINT16 Tcrit : 1; + } Bit; + UINT16 Data; + UINT8 Data8[2]; + } TsRegisterSet; + + MrcData = (MrcParameters *) This->SsaMemoryConfig.MrcData; + Inputs = &MrcData->SysIn.Inputs; + if (IsDimmPresent (MrcData, Socket, Controller, Channel, Dimm)) { + Address = SPD_SENSOR_BASE_ADDRESS | (Inputs->Controller[Controller].Channel[Channel].Dimm[Dimm].SpdAddress & 0xF); + if (mrcSuccess == MrcOemSmbusRead16 (Inputs->SmbusBaseAddress, Address, SPD_SENSOR_TEMPERATURE_OFFSET, &Value)) { + // Value read is in big endian format, convert it to little endian. + TsRegisterSet.Data = ((Value << 8) & 0xFF00) | ((Value >> 8) & 0xFF); + *Temperature = (TsRegisterSet.Bit.Sign) ? ((-1) * TsRegisterSet.Bit.Whole) : TsRegisterSet.Bit.Whole; + // SsaDebugPrint (PeiServices, This, SSA_D_INFO, "SSA GetMemTemp %u/%u/%u/%u %04Xh %04Xh %d\n", Socket, Controller, Channel, Dimm, Address, TsRegisterSet.Data, *Temperature); + return (Success); + } + } + *Temperature = 0; + return (NotAvailable); +} + +/** + +@brief + Sets the rank's mode register. + + @param[in, out] PeiServices - An indirect pointer to the PEI Services Table published by the PEI Foundation. + @param[in, out] This - Interface pointer that implements the particular SSA_BIOS_SERVICES_PPI instance. + @param[in] Socket - Zero based CPU socket number. + @param[in] Controller - Zero based controller number. + @param[in] Channel - Zero based channel number. + @param[in] Dimm - Zero based DIMM number. + @param[in] Rank - Zero based rank number in the DIMM. + @param[in] Address - Zero based mode register number. + @param[in] Data - Value to write to the register. + + @retval Success or failure code. + +**/ +static +SSA_STATUS +WriteMrs ( + EFI_PEI_SERVICES **PeiServices, + SSA_BIOS_SERVICES_PPI *This, + UINT8 Socket, + UINT8 Controller, + UINT8 Channel, + UINT8 Dimm, + UINT8 Rank, + UINT8 Address, + UINT16 Data + ) +{ + MrcParameters *MrcData; + U8 LogicalRank; + + MrcData = (MrcParameters *) This->SsaMemoryConfig.MrcData; + if (IsRankPresent (MrcData, Socket, Controller, Channel, Dimm, Rank)) { + LogicalRank = (Dimm * MAX_RANK_IN_DIMM) + Rank; +#ifdef ULT_FLAG + if (MrcData->SysOut.Outputs.DdrType == MRC_DDR_TYPE_LPDDR3) { + MrcIssueMrw (MrcData, Channel, LogicalRank, Address, Data, FALSE, FALSE); + } else +#endif + { + MrcWriteMRSAll (MrcData, Channel, MRC_BIT0 << LogicalRank, Address, &Data); + } + return (Success); + } + return (LogicalRankNotSupported); +} + +/** + +@brief + Restores the rank's mode register using the default value that the MRC has stored away. + + @param[in, out] PeiServices - An indirect pointer to the PEI Services Table published by the PEI Foundation. + @param[in, out] This - Interface pointer that implements the particular SSA_BIOS_SERVICES_PPI instance. + @param[in] Socket - Zero based CPU socket number. + @param[in] Controller - Zero based controller number. + @param[in] Channel - Zero based channel number. + @param[in] Dimm - Zero based DIMM number. + @param[in] Rank - Zero based rank number in the DIMM. + @param[in] Address - Zero based mode register number. + + @retval Success or failure code. + +**/ +static +SSA_STATUS +RestoreMrs ( + EFI_PEI_SERVICES **PeiServices, + SSA_BIOS_SERVICES_PPI *This, + UINT8 Socket, + UINT8 Controller, + UINT8 Channel, + UINT8 Dimm, + UINT8 Rank, + UINT8 Address + ) +{ + MrcParameters *MrcData; + UINT16 Data; + + MrcData = (MrcParameters *) This->SsaMemoryConfig.MrcData; + Data = MrcData->SysOut.Outputs.Controller[Controller].Channel[Channel].Dimm[Dimm].Rank[Rank].MR[Address]; + return (WriteMrs (PeiServices, This, Socket, Controller, Channel, Dimm, Rank, Address, Data)); +} + +/** + +@brief + Get the rank's mode register. + + @param[in, out] PeiServices - An indirect pointer to the PEI Services Table published by the PEI Foundation. + @param[in, out] This - Interface pointer that implements the particular SSA_BIOS_SERVICES_PPI instance. + @param[in] Socket - Zero based CPU socket number. + @param[in] Controller - Zero based controller number. + @param[in] Channel - Zero based channel number. + @param[in] Dimm - Zero based DIMM number. + @param[in] Rank - Zero based rank number in the DIMM. + @param[in] Address - Zero based mode register number. + @param[out] Data - Value read from the register. + + @retval Success or failure code. + +**/ +static +SSA_STATUS +ReadMrs ( + EFI_PEI_SERVICES **PeiServices, + SSA_BIOS_SERVICES_PPI *This, + UINT8 Socket, + UINT8 Controller, + UINT8 Channel, + UINT8 Dimm, + UINT8 Rank, + UINT8 Address, + UINT16 *Data + ) +{ + MrcParameters *MrcData; + SSA_STATUS Status; + + MrcData = (MrcParameters *) This->SsaMemoryConfig.MrcData; + if (IsRankPresent (MrcData, Socket, Controller, Channel, Dimm, Rank)) { + *Data = MrcData->SysOut.Outputs.Controller[Controller].Channel[Channel].Dimm[Dimm].Rank[Rank].MR[Address]; + Status = Success; + } else { + *Data = 0; + Status = LogicalRankNotSupported; + } + return (Status); +} + +/** + +@brief + Returns the DIMM number according to the rank number. + + @param[in, out] PeiServices - An indirect pointer to the PEI Services Table published by the PEI Foundation. + @param[in, out] This - Interface pointer that implements the particular SSA_BIOS_SERVICES_PPI instance. + @param[in] Socket - Zero based CPU socket number. + @param[in] Controller - Zero based controller number. + @param[in] Channel - Zero based channel number. + @param[in] Rank - Zero based rank number in the channel. + + @retval Returns the zero based DIMM index or FFh on error. + +**/ +static +UINT8 +GetDimmFromLogicalRank ( + EFI_PEI_SERVICES **PeiServices, + SSA_BIOS_SERVICES_PPI *This, + UINT8 Socket, + UINT8 Controller, + UINT8 Channel, + UINT8 Rank + ) +{ + MrcParameters *MrcData; + + MrcData = (MrcParameters *) This->SsaMemoryConfig.MrcData; + if (IsChannelPresent (MrcData, Socket, Controller, Channel) && (Rank < MAX_RANK_IN_CHANNEL)) { + return (Rank / MAX_RANK_IN_DIMM); + } + return ((UINT8) ~0); +} + +/** + +@brief + Gets DIMM information. + + @param[in, out] PeiServices - An indirect pointer to the PEI Services Table published by the PEI Foundation. + @param[in, out] This - Interface pointer that implements the particular SSA_BIOS_SERVICES_PPI instance. + @param[in] Socket - Zero based CPU socket number. + @param[in] Controller - Zero based controller number. + @param[in] Channel - Zero based channel number. + @param[in] Dimm - Zero based DIMM number. + @param[in, out] DimmInfoBuffer - Location to store DIMM information. + + @retval Returns DIMM information when a good status code is returned. + +**/ +static +SSA_STATUS +GetDimmInfo ( + EFI_PEI_SERVICES **PeiServices, + SSA_BIOS_SERVICES_PPI *This, + UINT8 Socket, + UINT8 Controller, + UINT8 Channel, + UINT8 Dimm, + MrcDimmInfo *DimmInfoBuffer + ) +{ + MrcDimmOut *DimmOut; + MrcParameters *MrcData; + + MrcData = (MrcParameters *) This->SsaMemoryConfig.MrcData; + if (IsDimmPresent (MrcData, Socket, Controller, Channel, Dimm)) { + DimmOut = &MrcData->SysOut.Outputs.Controller[Controller].Channel[Channel].Dimm[Dimm]; + DimmInfoBuffer->EccSupport = MrcData->SysOut.Outputs.EccSupport; + DimmInfoBuffer->DimmCapacity = DimmOut->DimmCapacity; + DimmInfoBuffer->RowSize = DimmOut->RowSize; + DimmInfoBuffer->ColumnSize = DimmOut->ColumnSize; + CopyMem (&DimmInfoBuffer->SerialNumber, + &MrcData->SysIn.Inputs.Controller[Controller].Channel[Channel].Dimm[Dimm].Spd.Ddr3.ModuleId, + sizeof (SPD_UNIQUE_MODULE_ID)); + return (Success); + } else { + SetMem (DimmInfoBuffer, 0, sizeof (MrcDimmInfo)); + return (NotAvailable); + } +} + +/** + +@brief + Returns the number of ranks in a specific DIMM on a given socket/controller. + + @param[in, out] PeiServices - An indirect pointer to the PEI Services Table published by the PEI Foundation. + @param[in, out] This - Interface pointer that implements the particular SSA_BIOS_SERVICES_PPI instance. + @param[in] Socket - Zero based CPU socket number. + @param[in] Controller - Zero based controller number. + @param[in] Channel - Zero based channel number. + @param[in] Dimm - Zero based DIMM number. + + @retval Returns the number of ranks in a specific DIMM on a given socket/controller. + +**/ +static +UINT8 +GetRankInDimm ( + EFI_PEI_SERVICES **PeiServices, + SSA_BIOS_SERVICES_PPI *This, + UINT8 Socket, + UINT8 Controller, + UINT8 Channel, + UINT8 Dimm + ) +{ + MrcParameters *MrcData; + + MrcData = (MrcParameters *) This->SsaMemoryConfig.MrcData; + return ((IsDimmPresent (MrcData, Socket, Controller, Channel, Dimm)) ? + MrcData->SysOut.Outputs.Controller[Controller].Channel[Channel].Dimm[Dimm].RankInDIMM : 0); +} + +/** + +@brief + Returns the bitmask of valid ranks on a given channel. + + @param[in, out] PeiServices - An indirect pointer to the PEI Services Table published by the PEI Foundation. + @param[in, out] This - Interface pointer that implements the particular SSA_BIOS_SERVICES_PPI instance. + @param[in] Socket - Zero based CPU socket number. + @param[in] Controller - Zero based controller number. + @param[in] Channel - Zero based channel number. + + @retval Returns the bitmask of valid ranks on a given channel. + +**/ +static +UINT8 +GetLogicalRankBitMask ( + EFI_PEI_SERVICES **PeiServices, + SSA_BIOS_SERVICES_PPI *This, + UINT8 Socket, + UINT8 Controller, + UINT8 Channel + ) +{ + MrcParameters *MrcData; + + MrcData = (MrcParameters *) This->SsaMemoryConfig.MrcData; + return ((IsChannelPresent (MrcData, Socket, Controller, Channel)) ? + MrcData->SysOut.Outputs.Controller[Controller].Channel[Channel].ValidRankBitMask : 0); +} + +/** + +@brief + Returns the channel bit mask of the populated channels. + + @param[in, out] PeiServices - An indirect pointer to the PEI Services Table published by the PEI Foundation. + @param[in, out] This - Interface pointer that implements the particular SSA_BIOS_SERVICES_PPI instance. + @param[in] Socket - Zero based CPU socket number. + @param[in] Controller - Zero based controller number. + + @retval Returns the channel bit mask of the populated channels. + +**/ +static +UINT8 +GetChannelBitMask ( + EFI_PEI_SERVICES **PeiServices, + SSA_BIOS_SERVICES_PPI *This, + UINT8 Socket, + UINT8 Controller + ) +{ + UINT8 Channel; + UINT8 ChannelMask; + MrcParameters *MrcData; + + MrcData = (MrcParameters *) This->SsaMemoryConfig.MrcData; + ChannelMask = 0; + for (Channel = 0; Channel < MAX_CHANNEL; Channel++) { + if (IsChannelPresent (MrcData, Socket, Controller, Channel)) { + ChannelMask |= (MRC_BIT0 << Channel); + } + } + return (ChannelMask); +} + +/** + +@brief + Gets information about the system. + + @param[in, out] PeiServices - An indirect pointer to the PEI Services Table published by the PEI Foundation. + @param[in, out] This - Interface pointer that implements the particular SSA_BIOS_SERVICES_PPI instance. + @param[in, out] SystemInfo - Pointer to buffer to be filled with system information. + + @retval Returns information about the system. + +**/ +static +SSA_STATUS +GetSystemInfo ( + EFI_PEI_SERVICES **PeiServices, + SSA_BIOS_SERVICES_PPI *This, + MrcSystemInfo *SystemInfoBuffer + ) +{ + SystemInfoBuffer->MaxNumberSockets = MAX_CPU_SOCKETS; + SystemInfoBuffer->MaxNumberControllers = MAX_CONTROLLERS; + SystemInfoBuffer->MaxNumberChannels = MAX_CHANNEL; + SystemInfoBuffer->MaxNumberLogicalRanks = MAX_RANK_IN_CHANNEL; + SystemInfoBuffer->SocketsBitMask = ((UINT32) (~0)) >> (32 - MAX_CPU_SOCKETS); + return (Success); +} + +/** + +@brief + Get a bit mask representing the present and enabled memory controllers in a CPU socket. + + @param[in, out] PeiServices - An indirect pointer to the PEI Services Table published by the PEI Foundation. + @param[in, out] This - Interface pointer that implements the particular SSA_BIOS_SERVICES_PPI instance. + @param[in] Socket - Zero based CPU socket number. + + @retval A bit mask representing the present and enabled memory controllers in a CPU socket. + +**/ +static +UINT8 +GetControllerBitMask ( + EFI_PEI_SERVICES **PeiServices, + SSA_BIOS_SERVICES_PPI *This, + UINT8 Socket + ) +{ + MrcParameters *MrcData; + + MrcData = (MrcParameters *) This->SsaMemoryConfig.MrcData; + return (IsSocketPresent (MrcData, Socket) ? (((UINT8) (~0)) >> (8 - MAX_CONTROLLERS)) : 0); +} + +/** + +@brief + Function used to reset a DIMM. + + @param[in, out] PeiServices - An indirect pointer to the PEI Services Table published by the PEI Foundation. + @param[in, out] This - Interface pointer that implements the particular SSA_BIOS_SERVICES_PPI instance. + @param[in] Socket - Zero based CPU socket number. + @param[in] Controller - Zero based controller number. + + @retval Nothing. + +**/ +static +VOID +JedecReset ( + EFI_PEI_SERVICES **PeiServices, + SSA_BIOS_SERVICES_PPI *This, + UINT8 Socket, + UINT8 Controller + ) +{ + MrcParameters *MrcData; + + MrcData = (MrcParameters *) This->SsaMemoryConfig.MrcData; + if (IsControllerPresent (MrcData, Socket, Controller)) { + MrcResetSequence (MrcData); + } + return; +} + +/** + +@brief + Function returns the low side range of a margin parameter. + + @param[in] IoLevel - Id of the I/O level to access. + @param[in] MarginGroup - Id of the margin group. Can be RxDq, TxDq, RxVref or TxVref. + + @retval Function returns the low side range of a margin parameter. + +**/ +static +INT16 +GetMarginParamMin ( + GSM_LT IoLevel, + GSM_GT MarginGroup + ) +{ + INT16 Value; + + switch (MarginGroup) { + case RxDqsDelay: + case TxDqsDelay: + Value = (-31); + break; + + case RxVref: + case TxVref: + Value = (-54); + break; + + default: + Value = INT16_MIN; + break; + } + return (Value); +} + +/** + +@brief + Function returns the high side range of a margin parameter. + + @param[in] IoLevel - Id of the I/O level to access. + @param[in] MarginGroup - Id of the margin group. Can be RxDq, TxDq, RxVref or TxVref. + + @retval Function returns the high side range of a margin parameter. + +**/ +static +INT16 +GetMarginParamMax ( + GSM_LT IoLevel, + GSM_GT MarginGroup + ) +{ + INT16 Value; + + switch (MarginGroup) { + case RxDqsDelay: + case TxDqsDelay: + Value = 31; + break; + + case RxVref: + case TxVref: + Value = 54; + break; + + default: + Value = INT16_MAX; + break; + } + return (Value); +} + +/** + +@brief + Function returns the minimum and maximum offsets that can be applied to the margin group + and the time delay in micro seconds for the new value to take effect. + + @param[in, out] PeiServices - An indirect pointer to the PEI Services Table published by the PEI Foundation. + @param[in, out] This - Interface pointer that implements the particular SSA_BIOS_SERVICES_PPI instance. + @param[in] Socket - Zero based CPU socket number. + @param[in] Controller - Zero based controller number. + @param[in] Channel - Zero based channel number. + @param[in] LogicRank - Zero based rank number in the channel. + @param[in] IoLevel - Id of the I/O level to access. + @param[in] MarginGroup - Id of the margin group. + @param[in] MinOffset - Minimum offset supported by the given margin group. + @param[in] MaxOffset - Maximum offset supported by the given margin group. + @param[out] Delay - Wait time in micro-seconds that is required for the new setting to take effect. + + @retval Success or error code. + +**/ +static +SSA_STATUS +GetMarginParamLimits ( + EFI_PEI_SERVICES **PeiServices, + SSA_BIOS_SERVICES_PPI *This, + UINT8 Socket, + UINT8 Controller, + UINT8 Channel, + UINT8 LogicRank, + GSM_LT IoLevel, + GSM_GT MarginGroup, + INT16 *MinOffset, + INT16 *MaxOffset, + UINT16 *Delay + ) +{ + MrcParameters *MrcData; + + MrcData = (MrcParameters *) This->SsaMemoryConfig.MrcData; + if (IsRankPresent (MrcData, Socket, Controller, Channel, LogicRank % MAX_RANK_IN_DIMM, LogicRank)) { + *MinOffset = GetMarginParamMin (IoLevel, MarginGroup); + *MaxOffset = GetMarginParamMax (IoLevel, MarginGroup); + *Delay = 0; + } + return (Success); +} + +/** + +@brief + Function used to adjust a margin parameter.It will add an offset from the training value + (if memory has been trained) or from the default value (if memory has not been trained yet). + + @param[in, out] PeiServices - An indirect pointer to the PEI Services Table published by the PEI Foundation. + @param[in, out] This - Interface pointer that implements the particular SSA_BIOS_SERVICES_PPI instance. + @param[in] Socket - Zero based CPU socket number. + @param[in] Controller - Zero based controller number. + @param[in] Channel - Zero based channel number. + @param[in] LogicRank - Zero based rank number in the channel. + @param[in] IoLevel - Id of the I/O level to access. + @param[in] MarginGroup - Id of the margin group. Can be RcvEna(0), RdT(1), WrT(2), WrDqsT(3), RdV(4) or WrV(5). + @param[in] Offset - Offset to be applied to the Margin parameter from the nominal. + + @retval Nothing. + +**/ +static +SSA_STATUS +OffsetMarginParam ( + EFI_PEI_SERVICES **PeiServices, + SSA_BIOS_SERVICES_PPI *This, + UINT8 Socket, + UINT8 Controller, + UINT8 Channel, + UINT8 LogicRank, + GSM_LT IoLevel, + GSM_GT MarginGroup, + UINT16 Offset + ) +{ + UINT8 Byte; + UINT8 ByteEnd; + MrcParameters *MrcData; + + MrcData = (MrcParameters *) This->SsaMemoryConfig.MrcData; + if (IsRankPresent (MrcData, Socket, Controller, Channel, LogicRank % MAX_RANK_IN_DIMM, LogicRank)) { + if (MarginGroup < WrLevel) { + ByteEnd = MrcData->SysOut.Outputs.SdramCount; + for (Byte = 0; Byte < ByteEnd; Byte++) { + if ((MarginGroup != WrV) || (Byte == 0)) { + ChangeMargin( + MrcData, + MarginGroup, // param + (S32) Offset, // value0 + 0, // value1 + 0, // EnMultiCast + Channel, // ch + LogicRank, // rank + Byte, // byte + 0, // bit + 0, // UpdateMrcData + 1, // SkipWait + MrcRegFileStart + ); + } // if + } // for + } else { + return (UnsupportedValue); + } // if + } else { + return (LogicalRankNotSupported); + } // if + return (Success); +} + +/** + +@brief + Function used to write to the Write Data Buffer (WDB). + + @param[in, out] PeiServices - An indirect pointer to the PEI Services Table published by the PEI Foundation. + @param[in, out] This - Interface pointer that implements the particular SSA_BIOS_SERVICES_PPI instance. + @param[in] Socket - Zero based CPU socket number. + @param[in] Controller - Zero based controller number. + @param[in] Channel - Zero based channel number. + @param[in] Pattern - Buffer containing the WDB pattern. + @param[in] CachelineCount - Size of the buffer pattern in term of the count of cachelines. + @param[in] StartCachelineIndex - Start offset on the WDB. + + @retval Nothing. + +**/ +static +VOID +SetWdbPattern ( + EFI_PEI_SERVICES **PeiServices, + SSA_BIOS_SERVICES_PPI *This, + UINT8 Socket, + UINT8 Controller, + UINT8 Channel, + UINT64 *Pattern, + UINT8 CachelineCount, + UINT8 StartCachelineIndex + ) +{ + UINT64_STRUCT *Pointer; + MCHBAR_CH0_CR_QCLK_LDAT_PDAT_STRUCT CrQclkLdatPdat; + MCHBAR_CH0_CR_QCLK_LDAT_SDAT_STRUCT CrQclkLdatSdat; + UINT32 CrQclkLdatDatain0Offset; + UINT32 CrQclkLdatDatain1Offset; + UINT32 CrQclkLdatSdatOffset; + UINT32 CrQclkLdatPdatOffset; + UINT8 PatternCachelineIdx; + UINT8 Chunk; + MrcParameters *MrcData; + + MrcData = (MrcParameters *) This->SsaMemoryConfig.MrcData; + if (IsChannelPresent (MrcData, Socket, Controller, Channel)) { + CrQclkLdatDatain0Offset = MCHBAR_CH0_CR_QCLK_LDAT_DATAIN_0_REG + + ((MCHBAR_CH1_CR_QCLK_LDAT_DATAIN_0_REG - MCHBAR_CH0_CR_QCLK_LDAT_DATAIN_0_REG) * Channel); + CrQclkLdatDatain1Offset = MCHBAR_CH0_CR_QCLK_LDAT_DATAIN_1_REG + + ((MCHBAR_CH1_CR_QCLK_LDAT_DATAIN_1_REG - MCHBAR_CH0_CR_QCLK_LDAT_DATAIN_1_REG) * Channel); + CrQclkLdatSdatOffset = MCHBAR_CH0_CR_QCLK_LDAT_SDAT_REG + + ((MCHBAR_CH1_CR_QCLK_LDAT_SDAT_REG - MCHBAR_CH0_CR_QCLK_LDAT_SDAT_REG) * Channel); + CrQclkLdatPdatOffset = MCHBAR_CH0_CR_QCLK_LDAT_PDAT_REG + + ((MCHBAR_CH1_CR_QCLK_LDAT_PDAT_REG - MCHBAR_CH0_CR_QCLK_LDAT_PDAT_REG) * Channel); + + CrQclkLdatSdat.Data = 0; + CrQclkLdatSdat.Bits.MODE = 1; + + CrQclkLdatPdat.Data = 0; + CrQclkLdatPdat.Bits.CMDB = MRC_BIT3; + + for (PatternCachelineIdx = 0; PatternCachelineIdx < CachelineCount; PatternCachelineIdx++) { + Pointer = (UINT64_STRUCT *) &Pattern[PatternCachelineIdx]; + for (Chunk = 0; Chunk < MAX_CHUNK_SIZE; Chunk++) { + WriteMem (PeiServices, This, RegWidth32, CrQclkLdatDatain0Offset, &Pointer[Chunk].Data32.Low); + WriteMem (PeiServices, This, RegWidth32, CrQclkLdatDatain1Offset, &Pointer[Chunk].Data32.High); + + // Set rep = 0, don't want to replicate the data. + // Set banksel field to the value of the chunk you want to write the 64 bits to. + // Set arraysel = 0 (indicating it is the MC WDB) and mode = 'b01 in the SDAT register. + CrQclkLdatSdat.Bits.BANKSEL = Chunk; + WriteMem (PeiServices, This, RegWidth32, CrQclkLdatSdatOffset, &CrQclkLdatSdat.Data); + + // Finally, write the PDAT register indicating which cacheline of the WDB you want to write to + // by setting fastaddr field to one of the 64 cache lines. Also set cmdb in the pdat register to 4'b1000, + // indicating that this is a LDAT write. + CrQclkLdatPdat.Bits.FASTADDR = StartCachelineIndex + PatternCachelineIdx; + WriteMem (PeiServices, This, RegWidth32, CrQclkLdatPdatOffset, &CrQclkLdatPdat.Data); + } // Chunk + + // Turn off LDAT mode after writing to WDB is complete. + CrQclkLdatSdat.Data = 0; + WriteMem (PeiServices, This, RegWidth32, CrQclkLdatSdatOffset, &CrQclkLdatSdat.Data); + } // PatternCachelineIdx + } + return; +} + +/** + +@brief + Function used to write to the CADB. + + @param[in, out] PeiServices - An indirect pointer to the PEI Services Table published by the PEI Foundation. + @param[in, out] This - Interface pointer that implements the particular SSA_BIOS_SERVICES_PPI instance. + @param[in] Socket - Zero based CPU socket number. + @param[in] Controller - Zero based controller number. + @param[in] Channel - Zero based channel number. + @param[in] Pattern - Buffer containing the WDB pattern. + @param[in] CachelineCount - Size of the buffer pattern in term of the count of cachelines. + @param[in] StartCachelineIndex - Start offset on the WDB. + + @retval Nothing. + +**/ +static +VOID +SetCadbPattern ( + EFI_PEI_SERVICES **PeiServices, + SSA_BIOS_SERVICES_PPI *This, + UINT8 Socket, + UINT8 Controller, + UINT8 Channel, + UINT64 *Pattern, + UINT8 CachelineCount, + UINT8 StartCachelineIndex + ) +{ + UINT32 Offset; + MrcParameters *MrcData; + + MrcData = (MrcParameters *) This->SsaMemoryConfig.MrcData; + if (IsChannelPresent (MrcData, Socket, Controller, Channel)) { + Offset = MCHBAR_CH0_CR_REUT_CH_PAT_CADB_WRITE_POINTER_REG + + ((MCHBAR_CH1_CR_REUT_CH_PAT_CADB_WRITE_POINTER_REG - MCHBAR_CH0_CR_REUT_CH_PAT_CADB_WRITE_POINTER_REG) * Channel); + MrcWriteCR (MrcData, Offset, StartCachelineIndex % MAX_CADB_ENTRIES); + + CachelineCount %= MAX_CADB_ENTRIES; + Offset = MCHBAR_CH0_CR_REUT_CH_PAT_CADB_PROG_REG + + ((MCHBAR_CH1_CR_REUT_CH_PAT_CADB_PROG_REG - MCHBAR_CH0_CR_REUT_CH_PAT_CADB_PROG_REG) * Channel); + while (CachelineCount--) { + // Write Row. CADB is auto incremented after every write + MrcWriteCR64 (MrcData, Offset, *Pattern++); + } + } + return; +} + +/** + +@brief + Function used to clear the lane error status registers. + + @param[in, out] PeiServices - An indirect pointer to the PEI Services Table published by the PEI Foundation. + @param[in, out] This - Interface pointer that implements the particular SSA_BIOS_SERVICES_PPI instance. + @param[in] Socket - Zero based CPU socket number. + @param[in] Controller - Zero based controller number. + @param[in] ChannelMask - Each bit represents a channel to be cleared. + + @retval Nothing. + +**/ +static +SSA_STATUS +ClearErrorStatus ( + EFI_PEI_SERVICES **PeiServices, + SSA_BIOS_SERVICES_PPI *This, + UINT8 Socket, + UINT8 Controller, + UINT8 ChannelMask + ) +{ + MCHBAR_CH0_CR_REUT_CH_ERR_DATA_STATUS_STRUCT CrReutChErrDataStatus; + MrcParameters *MrcData; + UINT8 Channel; + + MrcData = (MrcParameters *) This->SsaMemoryConfig.MrcData; + if (IsControllerPresent (MrcData, Socket, Controller)) { + if (ChannelMask > 0) { + Channel = 0; + while (ChannelMask) { + if ((ChannelMask & 1) && IsChannelPresent (MrcData, Socket, Controller, Channel)) { + CrReutChErrDataStatus.Data = 0; + WriteMem ( + PeiServices, + This, + RegWidth64, + MCHBAR_CH0_CR_REUT_CH_ERR_DATA_STATUS_REG + + (Channel * (MCHBAR_CH1_CR_REUT_CH_ERR_DATA_STATUS_REG - MCHBAR_CH0_CR_REUT_CH_ERR_DATA_STATUS_REG)), + &CrReutChErrDataStatus.Data); + } + Channel++; + ChannelMask >>= 1; + } + } else { + return (UnsupportedValue); + } + } else { + return (ControllerNotSupported); + } + return (Success); +} + +/** + +@brief + Function used to clear the error counter register. + + @param[in, out] PeiServices - An indirect pointer to the PEI Services Table published by the PEI Foundation. + @param[in, out] This - Interface pointer that implements the particular SSA_BIOS_SERVICES_PPI instance. + @param[in] Socket - Zero based CPU socket number. + @param[in] Controller - Zero based controller number. + @param[in] Channel - Zero based channel number. + @param[in] Counter - Zero based counter number. + + @retval Nothing. + +**/ +static +SSA_STATUS +ClearErrorCounter ( + EFI_PEI_SERVICES **PeiServices, + SSA_BIOS_SERVICES_PPI *This, + UINT8 Socket, + UINT8 Controller, + UINT8 Channel, + UINT8 Counter + ) +{ + MCHBAR_CH0_CR_REUT_CH_ERR_COUNTER_STATUS_0_STRUCT CrReutChErrCounterStatus0; + UINT32 Offset; + UINT8 Byte; + MrcParameters *MrcData; + + MrcData = (MrcParameters *) This->SsaMemoryConfig.MrcData; + if (IsChannelPresent (MrcData, Socket, Controller, Channel)) { + Offset = MCHBAR_CH0_CR_REUT_CH_ERR_COUNTER_STATUS_0_REG + + (Channel * (MCHBAR_CH1_CR_REUT_CH_ERR_COUNTER_STATUS_0_REG - MCHBAR_CH0_CR_REUT_CH_ERR_COUNTER_STATUS_0_REG)); + CrReutChErrCounterStatus0.Data = 0; + for (Byte = 0; Byte < MrcData->SysOut.Outputs.SdramCount; Byte++) { + WriteMem (PeiServices, This, RegWidth32, Offset, &CrReutChErrCounterStatus0.Data); + Offset += MCHBAR_CH0_CR_REUT_CH_ERR_COUNTER_STATUS_1_REG - MCHBAR_CH0_CR_REUT_CH_ERR_COUNTER_STATUS_0_REG; + } + } else { + return (ChannelNotSupported); + } + return (Success); +} + +/** + +@brief + Function used to get the DQ lane error status. + + @param[in, out] PeiServices - An indirect pointer to the PEI Services Table published by the PEI Foundation. + @param[in, out] This - Interface pointer that implements the particular SSA_BIOS_SERVICES_PPI instance. + @param[in] Socket - Zero based CPU socket number. + @param[in] Controller - Zero based controller number. + @param[in] Channel - Zero based channel number. + + @retval The DQ lane error status.. + +**/ +static +UINT64 +GetDqErrorStatus ( + EFI_PEI_SERVICES **PeiServices, + SSA_BIOS_SERVICES_PPI *This, + UINT8 Socket, + UINT8 Controller, + UINT8 Channel + ) +{ + MCHBAR_CH0_CR_REUT_CH_ERR_DATA_STATUS_STRUCT CrReutChErrDataStatus; + MrcParameters *MrcData; + + MrcData = (MrcParameters *) This->SsaMemoryConfig.MrcData; + CrReutChErrDataStatus.Data = 0; + if (IsChannelPresent (MrcData, Socket, Controller, Channel)) { + ReadMem ( + PeiServices, + This, + RegWidth64, + MCHBAR_CH0_CR_REUT_CH_ERR_DATA_STATUS_REG + + (Channel * (MCHBAR_CH1_CR_REUT_CH_ERR_DATA_STATUS_REG - MCHBAR_CH0_CR_REUT_CH_ERR_DATA_STATUS_REG)), + &CrReutChErrDataStatus.Data); + } + return (CrReutChErrDataStatus.Data); +} + +/** + +@brief + Function used to get the ECC lane error status. + + @param[in, out] PeiServices - An indirect pointer to the PEI Services Table published by the PEI Foundation. + @param[in, out] This - Interface pointer that implements the particular SSA_BIOS_SERVICES_PPI instance. + @param[in] Socket - Zero based CPU socket number. + @param[in] Controller - Zero based controller number. + @param[in] Channel - Zero based channel number. + + @retval Nothing. + +**/ +static +UINT8 +GetEccErrorStatus ( + EFI_PEI_SERVICES **PeiServices, + SSA_BIOS_SERVICES_PPI *This, + UINT8 Socket, + UINT8 Controller, + UINT8 Channel + ) +{ + MCHBAR_CH0_CR_REUT_CH_ERR_ECC_CHUNK_RANK_BYTE_NTH_STATUS_STRUCT Status; + MrcParameters *MrcData; + + MrcData = (MrcParameters *) This->SsaMemoryConfig.MrcData; + Status.Data = 0; + if (IsChannelPresent (MrcData, Socket, Controller, Channel)) { + ReadMem ( + PeiServices, + This, + RegWidth32, + MCHBAR_CH0_CR_REUT_CH_ERR_ECC_CHUNK_RANK_BYTE_NTH_STATUS_REG + + (Channel * (MCHBAR_CH1_CR_REUT_CH_ERR_ECC_CHUNK_RANK_BYTE_NTH_STATUS_REG - + MCHBAR_CH0_CR_REUT_CH_ERR_ECC_CHUNK_RANK_BYTE_NTH_STATUS_REG)), + &Status.Data); + } + return ((UINT8) Status.Bits.ECC_Error_Status); +} + +/** + +@brief + Function used to get the ECC lane error status. + + @param[in, out] PeiServices - An indirect pointer to the PEI Services Table published by the PEI Foundation. + @param[in, out] This - Interface pointer that implements the particular SSA_BIOS_SERVICES_PPI instance. + @param[in] Socket - Zero based CPU socket number. + @param[in] Controller - Zero based controller number. + @param[in] Channel - Zero based channel number. + @param[in] Counter - Zero based counter number. + @param[in] CounterMode - Enum that indicates the counter mode to be used. Count on all lanes, + count on a particular lane, count on a byte group, count on a particular chunk. + @param[in] ModeIndex - Extra index used to provide additional information if needed by the mode selected. + This indicates which lane, byte group or chunk has been selected. + + @retval Nothing. + +**/ +static +SSA_STATUS +SetErrorCounterMode ( + EFI_PEI_SERVICES **PeiServices, + SSA_BIOS_SERVICES_PPI *This, + UINT8 Socket, + UINT8 Controller, + UINT8 Channel, + UINT8 Counter, + COUNTER_MODE CounterMode, + UINT32 ModeIndex + ) +{ + UINT32 Offset; + MCHBAR_CH0_CR_REUT_CH_ERR_COUNTER_CTL_0_STRUCT ReutChErrCounterCtl; + MrcParameters *MrcData; + + MrcData = (MrcParameters *) This->SsaMemoryConfig.MrcData; + if (IsChannelPresent (MrcData, Socket, Controller, Channel)) { + ReutChErrCounterCtl.Data = 0; + switch (CounterMode) { + case AllLanes: + Offset = MCHBAR_CH0_CR_REUT_CH_ERR_COUNTER_CTL_0_REG + + ((MCHBAR_CH1_CR_REUT_CH_ERR_COUNTER_CTL_0_REG - MCHBAR_CH0_CR_REUT_CH_ERR_COUNTER_CTL_0_REG) * Channel); + break; + + case ParticularLane: + case ParticularByteGroup: + case ParticularChunk: + Offset = MCHBAR_CH0_CR_REUT_CH_ERR_COUNTER_CTL_0_REG + + ((MCHBAR_CH1_CR_REUT_CH_ERR_COUNTER_CTL_0_REG - MCHBAR_CH0_CR_REUT_CH_ERR_COUNTER_CTL_0_REG) * Channel) + + ((MCHBAR_CH0_CR_REUT_CH_ERR_COUNTER_CTL_1_REG - MCHBAR_CH0_CR_REUT_CH_ERR_COUNTER_CTL_0_REG) * Counter); + ReutChErrCounterCtl.Bits.Counter_Pointer = ModeIndex; + ReutChErrCounterCtl.Bits.Counter_Control = CounterMode; + break; + + default: + return (UnsupportedValue); + } + MrcWriteCR (MrcData, Offset, ReutChErrCounterCtl.Data); + } + return (Success); +} + +/** + +@brief + Function used to get the error count value for a given channel on a given socket/controller. + + @param[in, out] PeiServices - An indirect pointer to the PEI Services Table published by the PEI Foundation. + @param[in, out] This - Interface pointer that implements the particular SSA_BIOS_SERVICES_PPI instance. + @param[in] Socket - Zero based CPU socket number. + @param[in] Controller - Zero based controller number. + @param[in] Channel - Zero based channel number. + @param[in] Counter - Zero based counter number. + + @retval Nothing. + +**/ +static +ERROR_COUNT_32BITS +GetErrorCount ( + EFI_PEI_SERVICES **PeiServices, + SSA_BIOS_SERVICES_PPI *This, + UINT8 Socket, + UINT8 Controller, + UINT8 Channel, + UINT8 Counter + ) +{ + MCHBAR_CH0_CR_REUT_CH_ERR_COUNTER_STATUS_0_STRUCT CrReutErrCounterStatus0; + ERROR_COUNT_32BITS Count; + UINT32 Offset; + UINT8 Byte; + MrcParameters *MrcData; + + MrcData = (MrcParameters *) This->SsaMemoryConfig.MrcData; + Count.Data = 0; + if (IsChannelPresent (MrcData, Socket, Controller, Channel)) { + Offset = MCHBAR_CH0_CR_REUT_CH_ERR_COUNTER_STATUS_0_REG + + (Channel * (MCHBAR_CH1_CR_REUT_CH_ERR_COUNTER_STATUS_0_REG - MCHBAR_CH0_CR_REUT_CH_ERR_COUNTER_STATUS_0_REG)); + for (Byte = 0; Byte < MrcData->SysOut.Outputs.SdramCount; Byte++) { + ReadMem (PeiServices, This, RegWidth32, Offset, &CrReutErrCounterStatus0.Data); + Count.Data += CrReutErrCounterStatus0.Data; + Offset += MCHBAR_CH0_CR_REUT_CH_ERR_COUNTER_STATUS_1_REG - MCHBAR_CH0_CR_REUT_CH_ERR_COUNTER_STATUS_0_REG; + } + } + if (Count.Data > 0x7FFFFFFF) { + Count.Bits.Count = 0x7FFFFFFF; + Count.Bits.Overflow = 1; + } + + return (Count); +} + +/** + +@brief + Function used to set the lane validation mask for a give channel on a given socket/controller. + Only the lanes with the mask bit set will be checked for errors. + + @param[in, out] PeiServices - An indirect pointer to the PEI Services Table published by the PEI Foundation. + @param[in, out] This - Interface pointer that implements the particular SSA_BIOS_SERVICES_PPI instance. + @param[in] Socket - Zero based CPU socket number. + @param[in] Controller - Zero based controller number. + @param[in] Channel - Zero based channel number. + @param[in] DqMask - DQ lanes bitmask. + @param[in] EccMask - ECC lanes bitmask. + + @retval Nothing. + +**/ +static +VOID +SetValidationBitMask ( + EFI_PEI_SERVICES **PeiServices, + SSA_BIOS_SERVICES_PPI *This, + UINT8 Socket, + UINT8 Controller, + UINT8 Channel, + UINT64 DqMask, + UINT8 EccMask + ) +{ + MCHBAR_CH0_CR_REUT_CH_ERR_DATA_MASK_STRUCT CrReutErrDataMask; + MCHBAR_CH0_CR_REUT_CH_ERR_ECC_MASK_STRUCT CrReutChErrEccMask; + UINT32 Offset; + MrcParameters *MrcData; + + MrcData = (MrcParameters *) This->SsaMemoryConfig.MrcData; + if (IsChannelPresent (MrcData, Socket, Controller, Channel)) { + Offset = MCHBAR_CH0_CR_REUT_CH_ERR_DATA_MASK_REG + + ((MCHBAR_CH1_CR_REUT_CH_ERR_DATA_MASK_REG - MCHBAR_CH0_CR_REUT_CH_ERR_DATA_MASK_REG) * Channel); + CrReutErrDataMask.Data = ~DqMask; + WriteMem (PeiServices, This, RegWidth64, Offset, &CrReutErrDataMask.Data); + + Offset = MCHBAR_CH0_CR_REUT_CH_ERR_ECC_MASK_REG + + ((MCHBAR_CH1_CR_REUT_CH_ERR_ECC_MASK_REG - MCHBAR_CH0_CR_REUT_CH_ERR_ECC_MASK_REG) * Channel); + CrReutChErrEccMask.Data = ~EccMask; + WriteMem (PeiServices, This, RegWidth8, Offset, &CrReutChErrEccMask.Data); + } + return; +} + +/** + +@brief + Function used to set the phase mask for a give channel on a given socket/controller. + Only the phases with the mask bit set will be checked for errors. + + @param[in, out] PeiServices - An indirect pointer to the PEI Services Table published by the PEI Foundation. + @param[in, out] This - Interface pointer that implements the particular SSA_BIOS_SERVICES_PPI instance. + @param[in] Socket - Zero based CPU socket number. + @param[in] Controller - Zero based controller number. + @param[in] Channel - Zero based channel number. + @param[in] CachelineMask - Mask for the cacheline to be enabled. + @param[in] PhaseMask - Mask for the Phase. One bit for each phase. + + @retval Nothing. + +**/ +static +VOID +SetValidationPhaseMask ( + EFI_PEI_SERVICES **PeiServices, + SSA_BIOS_SERVICES_PPI *This, + UINT8 Socket, + UINT8 Controller, + UINT8 Channel, + UINT8 CachelineMask, + UINT8 PhaseMask + ) +{ + MCHBAR_CH0_CR_REUT_CH_ERR_CTL_STRUCT CrReutChErrCtl; + UINT32 Offset; + MrcParameters *MrcData; + + MrcData = (MrcParameters *) This->SsaMemoryConfig.MrcData; + if (IsChannelPresent (MrcData, Socket, Controller, Channel)) { + Offset = MCHBAR_CH0_CR_REUT_CH_ERR_CTL_REG + + ((MCHBAR_CH1_CR_REUT_CH_ERR_CTL_REG - MCHBAR_CH0_CR_REUT_CH_ERR_CTL_REG) * Channel); + CrReutChErrCtl.Data = 0; + CrReutChErrCtl.Bits.Selective_Error_Enable_Cacheline = CachelineMask; + CrReutChErrCtl.Bits.Selective_Error_Enable_Chunk = PhaseMask; + WriteMem (PeiServices, This, RegWidth32, Offset, &CrReutChErrCtl.Data); + } + return; +} + +/** + +@brief + Function used to run a point test. + + @param[in, out] PeiServices - An indirect pointer to the PEI Services Table published by the PEI Foundation. + @param[in, out] This - Interface pointer that implements the particular SSA_BIOS_SERVICES_PPI instance. + @param[in] Socket - Zero based CPU socket number. + @param[in] Controller - Zero based controller number. + @param[in] TestParameters - Architecture-specific test parameters. + @param[in] SkipSetup - Skip the test setup. It is OK to skip the setup after the first test. + + @retval Nothing. + +**/ +static +VOID +RunPointTest ( + EFI_PEI_SERVICES **PeiServices, + SSA_BIOS_SERVICES_PPI *This, + UINT8 Socket, + UINT8 Controller, + VOID *TestParameters, + BOOLEAN SkipSetup + ) +{ + const MRC_REUTAddress ReutAddress = { + {0, 0, 0, 0}, // Start + {0, 0, 0, 1023}, // Stop + {0, 0, 0, 0}, // Order + {0, 0, 0, 0}, // IncRate + {0, 0, 0, 1} // IncValue + }; + // IncRate, Start, Stop, DQPat + const MRC_WDBPattern CWdbPattern = { 16, 0, 1, BasicVA}; + + MCHBAR_CH0_CR_REUT_CH_PAT_WDB_CL_MUX_CFG_STRUCT CrReutChPatWdbClMuxCfg; + MCDFXS_CR_REUT_CH_SEQ_CFG_MCMAIN_0_STRUCT CrReutChSeqCfgMcMain0; + MCDFXS_CR_REUT_GLOBAL_CTL_MCMAIN_STRUCT CrReutGlobalCtl; + MCDFXS_CR_REUT_GLOBAL_ERR_MCMAIN_STRUCT CrReutGlobalErr; + MRC_WDBPattern WdbPattern; + POINT_TEST_PARAMETERS *Params; + UINT32 Offset; + UINT16 BurstLength; + UINT8 DumArr[7]; + UINT8 Channel; + UINT8 Rank; + UINT8 TargetRank; + UINT8 LoopCount; + MrcParameters *MrcData; + + MrcData = (MrcParameters *) This->SsaMemoryConfig.MrcData; + if (IsControllerPresent (MrcData, Socket, Controller)) { + CopyMem (&WdbPattern, &CWdbPattern, sizeof (MRC_WDBPattern)); + SetMem (DumArr, 1, sizeof (DumArr)); + Params = (POINT_TEST_PARAMETERS *) TestParameters; + + // Program the set up the test for each channel. + if (!SkipSetup) { + for (Channel = 0; Channel < MAX_CHANNEL; Channel++) { + if (IsChannelPresent (MrcData, Socket, Controller, Channel)) { + // Update the WDB pattern incRate, start and stop. + WdbPattern.IncRate = Params->WdbIncRates[Channel]; + WdbPattern.Stop = Params->WdbEnds[Channel]; + + // if (aggressor) traffic is WR or RD, need double the burst length to make it overlap with + // (victim) loopback traffic. + switch (Params->TrafficModes[Channel].Bits.TrafficMode) { + case TrafficModeWrite: // PatWr (Write Only) + case TrafficModeRead: // PatRd (Read Only) + BurstLength = Params->BurstLength * 2; + LoopCount = Params->LoopCount + 1; + break; + + case TrafficModeWrRd: // PatWrRd (Standard Write/Read Loopback) + default: + BurstLength = Params->BurstLength; + LoopCount = Params->LoopCount; + break; + } + SetupIOTest (MrcData, + (MRC_BIT0 << Channel), // ChbitMask, + Params->TrafficModes[Channel].Bits.TrafficMode, // CmdPat, + BurstLength, // NumCL, + LoopCount, // LC, + &ReutAddress, // REUTAddress, + Params->StopOnErr, // SOE, + &WdbPattern, // WDBPattern, + Params->EnCadb[Channel], // EnCADB, + 0, // EnCKE, + 0); // SubSeqWait + + // Set up LFSR or fix pattern modes. + if (Params->Modes[Channel].Bits.PatternMode == PatternModeFixed) { + // Sequentially walk through the WDB. + CrReutChPatWdbClMuxCfg.Data = 0; + CrReutChPatWdbClMuxCfg.Bits.Mux2_Control = 1; + CrReutChPatWdbClMuxCfg.Bits.Mux1_Control = 1; + CrReutChPatWdbClMuxCfg.Bits.Mux0_Control = 1; + CrReutChPatWdbClMuxCfg.Bits.ECC_Data_Source_Sel = 1; + Offset = MCHBAR_CH0_CR_REUT_CH_PAT_WDB_CL_MUX_CFG_REG + + ((MCHBAR_CH1_CR_REUT_CH_PAT_WDB_CL_MUX_CFG_REG - MCHBAR_CH0_CR_REUT_CH_PAT_WDB_CL_MUX_CFG_REG) * Channel); + WriteMem (PeiServices, This, RegWidth32, Offset, &CrReutChPatWdbClMuxCfg.Data); + } + + // Update the target rank. + TargetRank = 0; + for (Rank = 0; Rank < MAX_RANK_IN_CHANNEL; Rank++) { + // support one rank now + if (Params->Ranks[Channel] & (1 << Rank)) { + TargetRank = Rank; + break; + } + } // Rank + SelectReutRanks (MrcData, Channel, (1 << TargetRank), 0); + } // if + } // Channel + + // The SetupIOTest() disables channel's global control, we need to enable them. + for (Channel = 0; Channel < MAX_CHANNEL; Channel++) { + if (IsChannelPresent (MrcData, Socket, Controller, Channel)) { + Offset = MCDFXS_CR_REUT_CH_SEQ_CFG_MCMAIN_0_REG + + ((MCDFXS_CR_REUT_CH_SEQ_CFG_MCMAIN_1_REG - MCDFXS_CR_REUT_CH_SEQ_CFG_MCMAIN_0_REG) * Channel); + ReadMem (PeiServices, This, RegWidth64, Offset, &CrReutChSeqCfgMcMain0.Data); + CrReutChSeqCfgMcMain0.Bits.Global_Control = 1; + WriteMem (PeiServices, This, RegWidth64, Offset, &CrReutChSeqCfgMcMain0.Data); + } // if + } // Channel + + // Run test + RunIOTest (MrcData, // MrcParameters *MrcData, + 3, // U8 ChbitMask, + BasicVA, // U8 DQPat, + DumArr, // U8 *SeqLCs, + 0, // U8 ClearErrors, + 0); + } else { + // bypassSetup. Only issue test start bit. The not !bypassSetup needed to be called + // first to set up the system. + CrReutGlobalCtl.Data = 0; + CrReutGlobalCtl.Bits.Global_Start_Test = 1; + WriteMem (PeiServices, This, RegWidth32, MCDFXS_CR_REUT_GLOBAL_CTL_MCMAIN_REG, &CrReutGlobalCtl.Data); + + // Wait until channel test done. + do { + ReadMem (PeiServices, This, RegWidth32, MCDFXS_CR_REUT_GLOBAL_ERR_MCMAIN_REG, &CrReutGlobalErr.Data); + } + while (!CrReutGlobalErr.Bits.Channel_Test_Done_Status_0 || !CrReutGlobalErr.Bits.Channel_Test_Done_Status_1); + } + } + return; +} + +const SSA_BIOS_SERVICES_PPI SsaBiosServicesConst = { + { + SSA_REVISION_BIOS, + 0, // *SsaCommonConfig + 0, // *SsaMemoryConfig + }, + { + SSA_REVISION_COMMON, + 0, // MrcData + ReadMem, + WriteMem, + ReadIo, + WriteIo, + ReadPci, + WritePci, + GetBaseAddress, + Malloc, + Free, + SsaDebugPrint, + }, + { + SSA_REVISION_MEMORY, + 0, // MrcData + GetSystemInfo, + GetMemVoltage, + SetMemVoltage, + GetMemTemp, // @todo: not implemented yet + RestoreMrs, + WriteMrs, + ReadMrs, + GetDimmFromLogicalRank, + GetDimmInfo, + GetRankInDimm, + GetLogicalRankBitMask, + GetChannelBitMask, + GetControllerBitMask, + JedecReset, + GetMarginParamLimits, + OffsetMarginParam, + SetWdbPattern, + SetCadbPattern, + ClearErrorStatus, + ClearErrorCounter, + GetDqErrorStatus, + GetEccErrorStatus, + SetErrorCounterMode, + GetErrorCount, + SetValidationBitMask, + SetValidationPhaseMask, + RunPointTest + } +}; + +/** + +@brief + Initialize the SsaBiosServices data structure. + + @param[in] MrcData - The MRC global data area. + + @retval Nothing + +**/ +VOID +SsaBiosInitialize ( + IN MrcParameters *MrcData + ) +{ + EFI_PEI_SERVICES **PeiServices; + SSA_BIOS_SERVICES_PPI *SsaBiosServicesPpi; + EFI_PEI_PPI_DESCRIPTOR *SsaBiosServicesPpiDesc; + EFI_STATUS Status; + + SsaBiosServicesPpi = (SSA_BIOS_SERVICES_PPI *) AllocatePool (sizeof (SSA_BIOS_SERVICES_PPI)); + ASSERT (SsaBiosServicesPpi != NULL); + SsaBiosServicesPpiDesc = (EFI_PEI_PPI_DESCRIPTOR *) AllocatePool (sizeof (EFI_PEI_PPI_DESCRIPTOR)); + ASSERT (SsaBiosServicesPpiDesc != NULL); + + CopyMem (SsaBiosServicesPpi, &SsaBiosServicesConst, sizeof (SSA_BIOS_SERVICES_PPI)); + SsaBiosServicesPpi->SsaHeader.SsaCommonConfig = &SsaBiosServicesPpi->SsaCommonConfig; + SsaBiosServicesPpi->SsaHeader.SsaMemoryConfig = &SsaBiosServicesPpi->SsaMemoryConfig; + SsaBiosServicesPpi->SsaCommonConfig.BiosData = MrcData; + SsaBiosServicesPpi->SsaMemoryConfig.MrcData = MrcData; + + EfiCommonLibZeroMem (SsaBiosServicesPpiDesc, sizeof (EFI_PEI_PPI_DESCRIPTOR)); + SsaBiosServicesPpiDesc->Flags = EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST; + SsaBiosServicesPpiDesc->Guid = &gSsaBiosServicesPpiGuid; + SsaBiosServicesPpiDesc->Ppi = SsaBiosServicesPpi; + + PeiServices = (EFI_PEI_SERVICES **) MrcData->SysIn.Inputs.Debug.Stream; + Status = (**PeiServices).InstallPpi (PeiServices, SsaBiosServicesPpiDesc); + ASSERT_EFI_ERROR (Status); + + MRC_DEBUG_MSG (&MrcData->SysIn.Inputs.Debug, MSG_LEVEL_NOTE, "SSA Interface ready\n"); + + return; +} + +#endif // SSA_FLAG |