/* $NoKeywords:$ */ /** * @file * * mmConditionalPso.c * * Functions to support conditional entries in the Platform Specific Override Table * * @xrefitem bom "File Content Label" "Release Content" * @e project: AGESA * @e sub-project: (Mem/Main) * @e \$Revision: 44324 $ @e \$Date: 2010-12-22 17:16:51 +0800 (Wed, 22 Dec 2010) $ * **/ /***************************************************************************** * * Copyright (c) 2011, Advanced Micro Devices, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Advanced Micro Devices, Inc. nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *************************************************************************** * */ /* *---------------------------------------------------------------------------- * MODULES USED * *---------------------------------------------------------------------------- */ #include "AGESA.h" #include "amdlib.h" #include "OptionMemory.h" #include "PlatformMemoryConfiguration.h" #include "Ids.h" #include "Filecode.h" CODE_GROUP (G1_PEICC) RDATA_GROUP (G1_PEICC) #define FILECODE PROC_MEM_MAIN_MMCONDITIONALPSO_FILECODE /*---------------------------------------------------------------------------- * DEFINITIONS AND MACROS * *---------------------------------------------------------------------------- */ /*---------------------------------------------------------------------------- * TYPEDEFS AND STRUCTURES * *---------------------------------------------------------------------------- */ #define PSO_TYPE 0 #define PSO_LENGTH 1 #define PSO_DATA 2 typedef enum _PSO_STATE { PSO_FIND_CONDITION = 100, // Searching for initial Condition statement PSO_FIND_ACTION, // Searching for initial Action Statement PSO_MATCH_ACTION, // Trying to find an action that matches the caller's request PSO_CHECK_CONDITION, // Checking the condition that preceded the found action PSO_DO_ACTION, // Performing Action PSO_COMPLETE // Completed processing of this request } PSO_STATE; typedef struct _D3_CMP_CAL { UINT32 D3Cmp0NCal :3; UINT32 Reserved34 :2; UINT32 D3Cmp0PCal :3; UINT32 Reserved89 :2; UINT32 D3Cmp1NCal :3; UINT32 Reserved1314 :2; UINT32 D3Cmp1PCal :3; UINT32 Reserved1819 :2; UINT32 D3Cmp2NCal :3; UINT32 Reserved2324 :2; UINT32 D3Cmp2PCal :3; UINT32 Reserved2831 :2; } D3_CMP_CAL; /*---------------------------------------------------------------------------- * PROTOTYPES OF LOCAL FUNCTIONS * *---------------------------------------------------------------------------- */ BOOLEAN STATIC MemPSODoActionODT ( IN OUT MEM_NB_BLOCK *NBPtr, IN UINT8 *Buffer ); BOOLEAN STATIC MemPSODoActionAddrTmg ( IN OUT MEM_NB_BLOCK *NBPtr, IN UINT8 *Buffer ); BOOLEAN STATIC MemPSODoActionODCControl ( IN OUT MEM_NB_BLOCK *NBPtr, IN UINT8 *Buffer ); BOOLEAN STATIC MemPSODoActionSlewRate ( IN OUT MEM_NB_BLOCK *NBPtr, IN UINT8 *Buffer ); BOOLEAN STATIC MemPSODoActionGetFreqLimit ( IN OUT MEM_NB_BLOCK *NBPtr, IN UINT8 *Buffer ); BOOLEAN STATIC MemCheckRankType ( IN CH_DEF_STRUCT *CurrentChannel, IN UINT16 RankType ); /*---------------------------------------------------------------------------- * EXPORTED FUNCTIONS * *---------------------------------------------------------------------------- */ /* -----------------------------------------------------------------------------*/ /** * * Process Conditional Platform Specific Overrides * * @param[in] PlatformMemoryConfiguration - Pointer to Platform config table * @param[in] NBPtr - Pointer to Current NBBlock * @param[in] PsoAction - Action type * @param[in] Dimm - Dimm Number * * @return BOOLEAN - TRUE : Action was performed * FALSE: Action was not performed * * ---------------------------------------------------------------------------- */ BOOLEAN MemProcessConditionalOverrides ( IN PSO_TABLE *PlatformMemoryConfiguration, IN OUT MEM_NB_BLOCK *NBPtr, IN UINT8 PsoAction, IN UINT8 Dimm ) { BOOLEAN Result; MEM_TECH_BLOCK *TechPtr; UINT8 *Buffer; UINT8 *ConditionStartPtr; UINT8 *ActionStartPtr; UINT8 *SpdBufferPtr; UINT8 i; UINT8 DimmMask; UINT8 CurDimmMask; BOOLEAN Condition; BOOLEAN TmpCond; PSO_STATE State; ASSERT (PlatformMemoryConfiguration != NULL); ASSERT (NBPtr != NULL); ASSERT ((PsoAction >= PSO_ACTION_MIN) && (PsoAction <= PSO_ACTION_MAX)); // // Set up local data // TechPtr = NBPtr->TechPtr; Buffer = PlatformMemoryConfiguration; State = PSO_FIND_CONDITION; ConditionStartPtr = NULL; ActionStartPtr = NULL; Condition = FALSE; DimmMask = 0xFF; CurDimmMask = 0xFF; Result = FALSE; if (Dimm != 0xFF) { DimmMask = ( 1 << Dimm); } DimmMask &= (UINT8) (NBPtr->ChannelPtr->ChDimmValid & 0xFF); if (DimmMask == 0) { return Result; } // // Search for Condition Entry // while (State != PSO_COMPLETE) { switch (State) { // // Searching for initial Condition statement // case PSO_FIND_CONDITION: ASSERT (Buffer != NULL); while (Buffer[PSO_TYPE] != PSO_CONDITION_AND) { // // If end of table is reached, Change state to complete and break. // if (Buffer[PSO_TYPE] == PSO_END) { State = PSO_COMPLETE; break; } // // Otherwise, increment Buffer Pointer to the next PSO entry. // Buffer += (Buffer[PSO_LENGTH] + 2); } // // If Condition statement has been found, save the Condition Start Pointer, // and change to next state // if (State != PSO_COMPLETE) { ASSERT (Buffer != NULL); State = PSO_FIND_ACTION; ConditionStartPtr = Buffer; Buffer += (Buffer[PSO_LENGTH] + 2); } break; // // Searching for an action that matches the caller's request // case PSO_FIND_ACTION: ASSERT (Buffer != NULL); while (Buffer[PSO_TYPE] != PsoAction) { // // If non-conditional entry, change state to complete and break. // if ((Buffer[PSO_TYPE] < CONDITIONAL_PSO_MIN) || (Buffer[PSO_TYPE] > CONDITIONAL_PSO_MAX)) { State = PSO_COMPLETE; break; } // // Check for the Start of a new condition block // if (Buffer[PSO_TYPE] == PSO_CONDITION_AND) { ConditionStartPtr = Buffer; } // // Otherwise, increment buffer pointer to the next PSO entry. // Buffer += (Buffer[PSO_LENGTH] + 2); } // // If Action statement has been found, Save the Action Start Pointer, Reset Buffer to Condition Start // and Change to next state. // if (State != PSO_COMPLETE) { State = PSO_CHECK_CONDITION; ASSERT (Buffer != NULL); ActionStartPtr = Buffer; Buffer = ConditionStartPtr; Condition = TRUE; } break; // // Checking the condition that preceded the found action // case PSO_CHECK_CONDITION: ASSERT (Buffer != NULL); // // Point to the next Condition // Buffer += (Buffer[PSO_LENGTH] + 2); ASSERT ((Buffer[PSO_TYPE] >= CONDITIONAL_PSO_MIN) && (Buffer[PSO_TYPE] <= CONDITIONAL_PSO_MAX)); // // This section has already been checked for invalid statements so just exit on ACTION_xx // if ((Buffer[PSO_TYPE] >= PSO_ACTION_MIN) && (Buffer[PSO_TYPE] <= PSO_ACTION_MAX)) { if (Condition) { ASSERT (Buffer != NULL); State = PSO_DO_ACTION; // Perform the Action } else { State = PSO_FIND_CONDITION; // Go back and look for another condition/action } Buffer = ActionStartPtr; // Restore Action Pointer break; } switch (Buffer[PSO_TYPE]) { case PSO_CONDITION_AND: // // Additional CONDITION_AND is ORed with Previous ones, so if Previous result is TRUE // just restore action pointer and perform the action. // if (Condition) { State = PSO_DO_ACTION; Buffer = ActionStartPtr; } else { // // If its false, Start over and evaluate next cond. // reset the Current Dimm Mask // Condition = TRUE; CurDimmMask = 0xFF; } break; case PSO_CONDITION_LOC: // // Condition location // CurDimmMask = Buffer[4]; Condition &= ( ((Buffer[2] & (1 << (NBPtr->MCTPtr->SocketId))) != 0) && ((Buffer[3] & (1 << (NBPtr->ChannelPtr->ChannelID))) != 0) && ((CurDimmMask & DimmMask) != 0) ); break; case PSO_CONDITION_SPD: // // Condition SPD // TmpCond = FALSE; for (i = 0; i < MAX_DIMMS_PER_CHANNEL; i ++) { if ( ((DimmMask & CurDimmMask) & ((UINT16) (1 << i))) != 0) { if (TechPtr->GetDimmSpdBuffer (TechPtr, &SpdBufferPtr, i)) { TmpCond |= ( (SpdBufferPtr[Buffer[2]] & Buffer[3]) == Buffer[4]); } } } Condition &= TmpCond; break; case PSO_CONDITION_REG: // // Condition Register - unsupported at this time // break; default: ASSERT (FALSE); } // End Condition Switch break; case PSO_DO_ACTION: ASSERT (Buffer != NULL); // // Performing Action // if ((Buffer[PSO_TYPE] < PSO_ACTION_MIN) || (Buffer[PSO_TYPE] > PSO_ACTION_MAX)) { State = PSO_COMPLETE; } if (Buffer[PSO_TYPE] == PsoAction) { switch (Buffer[PSO_TYPE]) { case PSO_ACTION_ODT: Result = MemPSODoActionODT (NBPtr, &Buffer[PSO_DATA]); break; case PSO_ACTION_ADDRTMG: Result = MemPSODoActionAddrTmg (NBPtr, &Buffer[PSO_DATA]); break; case PSO_ACTION_ODCCONTROL: Result = MemPSODoActionODCControl (NBPtr, &Buffer[PSO_DATA]); break; case PSO_ACTION_SLEWRATE: Result = MemPSODoActionSlewRate (NBPtr, &Buffer[PSO_DATA]); break; case PSO_ACTION_SPEEDLIMIT: Result = MemPSODoActionGetFreqLimit (NBPtr, &Buffer[PSO_DATA]); break; case PSO_ACTION_REG: break; default: ASSERT (FALSE); } // End Action Switch // // If Action was performed, mark complete. // if (Result) { State = PSO_COMPLETE; } }// End Action // // Point to the next PSO Entry // Buffer += (Buffer[PSO_LENGTH] + 2); break; case PSO_COMPLETE: // // Completed processing of this request // break; default: ASSERT (FALSE); } // End State Switch } // End While return Result; } /*---------------------------------------------------------------------------- * LOCAL FUNCTIONS * *---------------------------------------------------------------------------- */ /* -----------------------------------------------------------------------------*/ /** * Perform ODT Platform Override * * @param[in] NBPtr - Pointer to Current NBBlock * @param[in] Buffer - Pointer to the Action Command Data (w/o Type and Len) * * @return BOOLEAN - TRUE : Action was performed * FALSE: Action was not performed * * ---------------------------------------------------------------------------- */ BOOLEAN STATIC MemPSODoActionODT ( IN OUT MEM_NB_BLOCK *NBPtr, IN UINT8 *Buffer ) { BOOLEAN Result; UINT32 Speed; UINT8 Dimms; UINT8 i; UINT8 QR_Dimms; Result = FALSE; Speed = ((UINT32) 1 << (NBPtr->DCTPtr->Timings.Speed / 66)); Dimms = NBPtr->ChannelPtr->Dimms; QR_Dimms = 0; for (i = 0; i < MAX_DIMMS_PER_CHANNEL; i++) { if (((NBPtr->ChannelPtr->DimmQrPresent & (UINT16) (1 << i)) != 0) && (i < 2)) { QR_Dimms ++; } } if ((Speed & ((UINT32 *) Buffer)[0]) != 0) { if ((((UINT8) (1 << (Dimms - 1)) & Buffer[4]) != 0) || (Buffer[4] == ANY_NUM)) { if (((QR_Dimms == 0) && (Buffer[5] == NO_DIMM)) || ((QR_Dimms > 0) && (((UINT8) (1 << (QR_Dimms - 1)) & Buffer[5]) != 0)) || (Buffer[5] == ANY_NUM)) { NBPtr->PsPtr->DramTerm = Buffer[6]; NBPtr->PsPtr->QR_DramTerm = Buffer[7]; NBPtr->PsPtr->DynamicDramTerm = Buffer[8]; Result = TRUE; IDS_HDT_CONSOLE (MEM_FLOW, " Platform Override: DramTerm:%02x, QRDramTerm:%02x, DynDramTerm:%02x\n", Buffer[6], Buffer[7], Buffer[8]); } } } return Result; } /* -----------------------------------------------------------------------------*/ /** * Perform Address Timing Platform Override * * @param[in] NBPtr - Pointer to Current NBBlock * @param[in] Buffer - Pointer to the Action Command Data (w/o Type and Len) * * @return BOOLEAN - TRUE : Action was performed * FALSE: Action was not performed * * ---------------------------------------------------------------------------- */ BOOLEAN STATIC MemPSODoActionAddrTmg ( IN OUT MEM_NB_BLOCK *NBPtr, IN UINT8 *Buffer ) { BOOLEAN Result; CH_DEF_STRUCT *ChannelPtr; UINT32 Speed; UINT16 DimmConfig; Result = FALSE; ChannelPtr = NBPtr->ChannelPtr; Speed = ((UINT32) 1 << (NBPtr->DCTPtr->Timings.Speed / 66)); DimmConfig = *(UINT16 *) &(Buffer[4]); if ((Speed & ((UINT32 *) Buffer)[0]) != 0) { if (MemCheckRankType (ChannelPtr, DimmConfig)) { ChannelPtr->DctAddrTmg = *(UINT32*) &(Buffer[6]); Result = TRUE; IDS_HDT_CONSOLE (MEM_FLOW, " Platform Override: Address Timing:%08x\n", *(UINT32*) &(Buffer[6])); } } return Result; } /* -----------------------------------------------------------------------------*/ /** * Perform Drive Strength Platform Override * * @param[in] NBPtr - Pointer to Current NBBlock * @param[in] Buffer - Pointer to the Action Command Data (w/o Type and Len) * * @return BOOLEAN - TRUE : Action was performed * FALSE: Action was not performed * * ---------------------------------------------------------------------------- */ BOOLEAN STATIC MemPSODoActionODCControl ( IN OUT MEM_NB_BLOCK *NBPtr, IN UINT8 *Buffer ) { BOOLEAN Result; CH_DEF_STRUCT *ChannelPtr; UINT32 Speed; UINT16 DimmConfig; Result = FALSE; ChannelPtr = NBPtr->ChannelPtr; Speed = ((UINT32) 1 << (NBPtr->DCTPtr->Timings.Speed / 66)); DimmConfig = *(UINT16 *) &(Buffer[4]); if ((Speed & ((UINT32 *) Buffer)[0]) != 0) { if (MemCheckRankType (ChannelPtr, DimmConfig)) { ChannelPtr->DctOdcCtl = *(UINT32*) &(Buffer[6]); Result = TRUE; IDS_HDT_CONSOLE (MEM_FLOW, " Platform Override: ODC Control:%08x\n", *(UINT32*)&(Buffer[6])); } } return Result; } /* -----------------------------------------------------------------------------*/ /** * Perform Slew Rate Platform Override * * @param[in] NBPtr - Pointer to Current NBBlock * @param[in] Buffer - Pointer to the Action Command Data (w/o Type and Len) * * @return BOOLEAN - TRUE : Action was performed * FALSE: Action was not performed * * ---------------------------------------------------------------------------- */ BOOLEAN STATIC MemPSODoActionSlewRate ( IN OUT MEM_NB_BLOCK *NBPtr, IN UINT8 *Buffer ) { BOOLEAN Result; CH_DEF_STRUCT *ChannelPtr; UINT32 Speed; UINT16 DimmConfig; Result = FALSE; ChannelPtr = NBPtr->ChannelPtr; Speed = ((UINT32) 1 << (NBPtr->DCTPtr->Timings.Speed / 66)); DimmConfig = *(UINT16 *) &(Buffer[4]); if ((Speed & ((UINT32 *) Buffer)[0]) != 0) { if (MemCheckRankType (ChannelPtr, DimmConfig)) { MemNSetBitFieldNb (NBPtr, BFD3Cmp0NCal, ((D3_CMP_CAL *) &(Buffer[6]))->D3Cmp0NCal ); MemNSetBitFieldNb (NBPtr, BFD3Cmp0PCal, ((D3_CMP_CAL *) &(Buffer[6]))->D3Cmp0PCal ); MemNSetBitFieldNb (NBPtr, BFD3Cmp1NCal, ((D3_CMP_CAL *) &(Buffer[6]))->D3Cmp1NCal ); MemNSetBitFieldNb (NBPtr, BFD3Cmp1PCal, ((D3_CMP_CAL *) &(Buffer[6]))->D3Cmp1PCal ); MemNSetBitFieldNb (NBPtr, BFD3Cmp2NCal, ((D3_CMP_CAL *) &(Buffer[6]))->D3Cmp2NCal ); MemNSetBitFieldNb (NBPtr, BFD3Cmp2PCal, ((D3_CMP_CAL *) &(Buffer[6]))->D3Cmp2PCal ); Result = TRUE; IDS_HDT_CONSOLE (MEM_FLOW, " Platform Override: Slew Rate:%08x\n", *(UINT32 *) &(Buffer[6])); } } return Result; } /* -----------------------------------------------------------------------------*/ /** * * This function overrides the POR supported speed for a specific config * * @param[in] NBPtr - Pointer to Current NBBlock * @param[in] Buffer - Pointer to the Action Command Data (w/o Type and Len) * * @return BOOLEAN - TRUE : Action was performed * FALSE: Action was not performed * */ BOOLEAN STATIC MemPSODoActionGetFreqLimit ( IN OUT MEM_NB_BLOCK *NBPtr, IN UINT8 *Buffer ) { BOOLEAN Result; CH_DEF_STRUCT *ChannelPtr; DCT_STRUCT *DCTPtr; UINT16 DimmConfig; UINT16 SpeedLimit; Result = FALSE; ChannelPtr = NBPtr->ChannelPtr; DCTPtr = NBPtr->DCTPtr; DimmConfig = *(UINT16*) &(Buffer[0]); SpeedLimit = 0; // // Match number of dimms, then Rank Type // if (ChannelPtr->Dimms == Buffer[2]) { if (MemCheckRankType (ChannelPtr, DimmConfig)) { // // Select speed based on current voltage // if (NBPtr->RefPtr->DDR3Voltage == VOLT1_5) { SpeedLimit = *(UINT16*) &(Buffer[3]); } else if (NBPtr->RefPtr->DDR3Voltage == VOLT1_25) { SpeedLimit = *(UINT16*) &(Buffer[7]); } else { SpeedLimit = *(UINT16*) &(Buffer[5]); } // // Set the Speed limit // if (DCTPtr->Timings.TargetSpeed > SpeedLimit) { DCTPtr->Timings.TargetSpeed = SpeedLimit; } Result = TRUE; IDS_HDT_CONSOLE (MEM_FLOW, " Platform Override: Max Memory Speed for Channel %d: %d\n", NBPtr->Channel, SpeedLimit); } } return Result; } /* -----------------------------------------------------------------------------*/ /** * * This function matches a particular Rank Type Mask to the installed * DIMM configuration on the provided channel. * * @param[in] *CurrentChannel Pointer to CH_DEF_STRUCT * @param[in] RankType Mask of rank type to match * * @return BOOLEAN - TRUE : Rank types match * FALSE: Rank types do not match * */ BOOLEAN STATIC MemCheckRankType ( IN CH_DEF_STRUCT *CurrentChannel, IN UINT16 RankType ) { BOOLEAN Result; UINT8 i; UINT16 DIMMRankType; DIMMRankType = MemAGetPsRankType (CurrentChannel); Result = TRUE; for (i = 0; i < MAX_DIMMS_PER_CHANNEL; i++) { if ( ((DIMMRankType & (0x0F << (i << 2))) + (RankType & (0x0F << (i << 2)))) != 0) { Result &= (((DIMMRankType & (0x0F << (i << 2))) & ( RankType & ( 0x0F << ( i << 2)))) != 0); } if (!Result) { break; } } return Result; }