/** * * Find the common supported voltage on all nodes. * * @param[in,out] *MemMainPtr - Pointer to the MEM_MAIN_DATA_BLOCK * * @return TRUE - No fatal error occurs. * @return FALSE - Fatal error occurs. */ STATIC BOOLEAN MemMLvDdr3 ( IN OUT MEM_MAIN_DATA_BLOCK *MemMainPtr ) { UINT8 Node; BOOLEAN RetVal; BOOLEAN SecondLoop; MEM_NB_BLOCK *NBPtr; MEM_PARAMETER_STRUCT *ParameterPtr; MEM_SHARED_DATA *mmSharedPtr; NBPtr = MemMainPtr->NBPtr; mmSharedPtr = MemMainPtr->mmSharedPtr; ParameterPtr = MemMainPtr->MemPtr->ParameterListPtr; mmSharedPtr->VoltageMap = 0xFF; SecondLoop = FALSE; RetVal = TRUE; for (Node = 0; Node < MemMainPtr->DieCount; Node++) { NBPtr[Node].FeatPtr->LvDdr3 (&NBPtr[Node]); // Check if there is no common supported voltage if ((mmSharedPtr->VoltageMap == 0) && !SecondLoop) { // restart node loop by setting node to 0xFF Node = 0xFF; SecondLoop = TRUE; } } if (mmSharedPtr->VoltageMap == 0) { IDS_HDT_CONSOLE (MEM_FLOW, "\nNo commonly supported VDDIO is found.\n"); PutEventLog (AGESA_WARNING, MEM_WARNING_NO_COMMONLY_SUPPORTED_VDDIO, 0, 0, 0, 0, &(NBPtr[BSP_DIE].MemPtr->StdHeader)); SetMemError (AGESA_WARNING, NBPtr[BSP_DIE].MCTPtr); // When there is no commonly supported VDDIO, use 1.35V as the temporal VDDIO ParameterPtr->DDR3Voltage = VOLT1_35; } else { IDS_HDT_CONSOLE (MEM_FLOW, "\nCommonly supported VDDIO is: %s%s%s.\n", ((mmSharedPtr->VoltageMap & 1) != 0) ? "1.5V, " : "", ((mmSharedPtr->VoltageMap & 2) != 0) ? "1.35V, " : "", ((mmSharedPtr->VoltageMap & 4) != 0) ? "1.25V" : ""); ParameterPtr->DDR3Voltage = CONVERT_ENCODED_TO_VDDIO (LibAmdBitScanReverse (mmSharedPtr->VoltageMap)); } for (Node = 0; Node < MemMainPtr->DieCount; Node ++) { // Check if the voltage needs force to 1.5V NBPtr[Node].FamilySpecificHook[ForceLvDimmVoltage] (&NBPtr[Node], MemMainPtr); RetVal &= (BOOLEAN) (NBPtr[Node].MCTPtr->ErrCode < AGESA_FATAL); } return RetVal; }
/** * RX offset cancellation enablement * * * * @param[in] Wrapper Pointer to Wrapper configuration data area * @param[in] Pcie Pointer to PCIe configuration data area */ VOID PcieOffsetCancelCalibration ( IN PCIe_WRAPPER_CONFIG *Wrapper, IN PCIe_PLATFORM_CONFIG *Pcie ) { UINT32 LaneBitmap; D0F0xBC_x1F39C_STRUCT D0F0xBC_x1F39C; LaneBitmap = PcieUtilGetWrapperLaneBitMap (LANE_TYPE_PHY_NATIVE_ALL, LANE_TYPE_PCIE_SB_CORE_CONFIG, Wrapper); if ((Wrapper->WrapId != GFX_WRAP_ID) && (Wrapper->WrapId != GPP_WRAP_ID)) { return; } if (LaneBitmap != 0) { D0F0xBC_x1F39C.Value = 0; D0F0xBC_x1F39C.Field.Tx = 1; D0F0xBC_x1F39C.Field.Rx = 1; D0F0xBC_x1F39C.Field.UpperLaneID = LibAmdBitScanReverse (LaneBitmap) + Wrapper->StartPhyLane; D0F0xBC_x1F39C.Field.LowerLaneID = LibAmdBitScanForward (LaneBitmap) + Wrapper->StartPhyLane; GnbRegisterWriteTN (D0F0xBC_x1F39C_TYPE, D0F0xBC_x1F39C_ADDRESS, &D0F0xBC_x1F39C.Value, GNB_REG_ACC_FLAG_S3SAVE, GnbLibGetHeader (Pcie)); GnbSmuServiceRequestV4 ( PcieConfigGetParentSilicon (Wrapper)->Address, SMC_MSG_PHY_LN_OFF, GNB_REG_ACC_FLAG_S3SAVE, GnbLibGetHeader (Pcie) ); GnbSmuServiceRequestV4 ( PcieConfigGetParentSilicon (Wrapper)->Address, SMC_MSG_PHY_LN_ON, GNB_REG_ACC_FLAG_S3SAVE, GnbLibGetHeader (Pcie) ); } PcieTopologyLaneControl ( EnableLanes, PcieUtilGetWrapperLaneBitMap (LANE_TYPE_ALL, 0, Wrapper), Wrapper, Pcie ); }
/** * * Find the common supported voltage on all nodes. * * @param[in,out] *MemMainPtr - Pointer to the MEM_MAIN_DATA_BLOCK * * @return TRUE - No fatal error occurs. * @return FALSE - Fatal error occurs. */ BOOLEAN MemMLvDdr3 ( IN OUT MEM_MAIN_DATA_BLOCK *MemMainPtr ) { UINT8 Node; BOOLEAN RetVal; BOOLEAN SecondLoop; MEM_NB_BLOCK *NBPtr; MEM_PARAMETER_STRUCT *ParameterPtr; MEM_SHARED_DATA *mmSharedPtr; NBPtr = MemMainPtr->NBPtr; mmSharedPtr = MemMainPtr->mmSharedPtr; ParameterPtr = MemMainPtr->MemPtr->ParameterListPtr; mmSharedPtr->VoltageMap = 0xFF; SecondLoop = FALSE; RetVal = TRUE; for (Node = 0; Node < MemMainPtr->DieCount; Node++) { NBPtr[Node].FeatPtr->LvDdr3 (&NBPtr[Node]); // Check if there is no common supported voltage if ((mmSharedPtr->VoltageMap == 0) && !SecondLoop) { // restart node loop by setting node to 0xFF Node = 0xFF; SecondLoop = TRUE; } } if (mmSharedPtr->VoltageMap == 0) { ParameterPtr->DDR3Voltage = VOLT_UNSUPPORTED; } else { ParameterPtr->DDR3Voltage = (DIMM_VOLTAGE) LibAmdBitScanReverse (mmSharedPtr->VoltageMap); } for (Node = 0; Node < MemMainPtr->DieCount; Node ++) { RetVal &= (BOOLEAN) (NBPtr[Node].MCTPtr->ErrCode < AGESA_FATAL); } return RetVal; }
AGESA_STATUS PcieFP2x8CheckCallbackTN ( IN PCIe_WRAPPER_CONFIG *Wrapper, IN OUT VOID *Buffer, IN PCIe_PLATFORM_CONFIG *Pcie ) { UINT32 LaneBitmap; AGESA_STATUS Status; IDS_HDT_CONSOLE (GNB_TRACE, "PcieFP2x8CheckCallbackTN Enter\n"); Status = AGESA_SUCCESS; if (Wrapper->WrapId == GFX_WRAP_ID) { LaneBitmap = PcieUtilGetWrapperLaneBitMap (LANE_TYPE_PCIE_PHY_NATIVE | LANE_TYPE_DDI_PHY_NATIVE, 0, Wrapper); IDS_HDT_CONSOLE (GNB_TRACE, "FP2 GFX Wrpper phy LaneBitmap = %x\n", LaneBitmap); if (((LaneBitmap & 0xFF) != 0) && ((LaneBitmap & 0xFF00) != 0)) { IDS_HDT_CONSOLE (GNB_TRACE, "Error!! FP2 GFX Wrpper cannot use both phy#\n"); Status = AGESA_ERROR; PcieConfigDisableAllEngines (PciePortEngine | PcieDdiEngine, Wrapper); PutEventLog ( AGESA_ERROR, GNB_EVENT_INVALID_LANES_CONFIGURATION, (LibAmdBitScanForward (LaneBitmap) + Wrapper->StartPhyLane), (LibAmdBitScanReverse (LaneBitmap) + Wrapper->StartPhyLane), 0, 0, GnbLibGetHeader (Pcie) ); ASSERT (FALSE); } } IDS_HDT_CONSOLE (GNB_TRACE, "PcieFP2x8CheckCallbackTN Exit\n"); return Status; }
/** * Retry must be enabled on all coherent links if it is enabled on any coherent links. * * @HtFeatMethod{::F_SET_LINK_DATA} * * Effectively, this means HT3 on some links cannot be mixed with HT1 on others. * Scan the CPU to CPU links for this condition and limit those frequencies to HT1 * if it is detected. * (Non-coherent links are independent.) * * @param[in,out] State global state, port frequency settings. * * @retval TRUE Fixup occurred, all coherent links HT1 * @retval FALSE No changes */ BOOLEAN IsCoherentRetryFixup ( IN STATE_DATA *State ) { UINT8 Freq; UINT8 i; UINT8 DetectedFrequencyState; BOOLEAN IsMixed; UINT32 Temp; // // detectedFrequencyState: // 0 - initial state // 1 - HT1 Frequencies detected // 2 - HT3 Frequencies detected // IsMixed = FALSE; DetectedFrequencyState = 0; // Scan coherent links for a mix of HT3 / HT1 for (i = 0; i < (State->TotalLinks * 2); i += 2) { if (((*State->PortList)[i].Type == PORTLIST_TYPE_CPU) && ((*State->PortList)[i + 1].Type == PORTLIST_TYPE_CPU)) { // At this point, Frequency of port [i+1] must equal [i], so just check one of them. switch (DetectedFrequencyState) { case 0: // Set current state to indicate what link frequency we found first if ((*State->PortList)[i].SelFrequency > HT_FREQUENCY_1000M) { // HT3 frequencies DetectedFrequencyState = 2; } else { // HT1 frequencies DetectedFrequencyState = 1; } break; case 1: // If HT1 frequency detected, fail any HT3 frequency if ((*State->PortList)[i].SelFrequency > HT_FREQUENCY_1000M) { IsMixed = TRUE; } break; case 2: // If HT3 frequency detected, fail any HT1 frequency if ((*State->PortList)[i].SelFrequency <= HT_FREQUENCY_1000M) { IsMixed = TRUE; } break; default: ASSERT (FALSE); } if (IsMixed) { // Don't need to keep checking after we find a mix. break; } } } if (IsMixed) { for (i = 0; i < (State->TotalLinks * 2); i += 2) { if (((*State->PortList)[i].Type == PORTLIST_TYPE_CPU) && ((*State->PortList)[i + 1].Type == PORTLIST_TYPE_CPU)) { // Limit coherent links to HT 1 frequencies. Temp = (*State->PortList)[i].CompositeFrequencyCap & (*State->PortList)[i + 1].CompositeFrequencyCap; Temp &= HT_FREQUENCY_LIMIT_HT1_ONLY; ASSERT (Temp != 0); (*State->PortList)[i].CompositeFrequencyCap = Temp; (*State->PortList)[i + 1].CompositeFrequencyCap = Temp; Freq = LibAmdBitScanReverse (Temp); (*State->PortList)[i].SelFrequency = Freq; (*State->PortList)[i + 1].SelFrequency = Freq; } } } return (IsMixed); }
/** * Optimize Links. * * @HtFeatMethod{::F_SELECT_OPTIMAL_WIDTH_AND_FREQUENCY} * * For all Links: * Examine both sides of a Link and determine the optimal frequency and width, * taking into account externally provided limits and enforcing any other limit * or matching rules as applicable except subLink balancing. Update the port * list data with the optimal settings. * * @note no hardware state changes in this routine. * * @param[in,out] State Process and update portlist */ VOID SelectOptimalWidthAndFrequency ( IN OUT STATE_DATA *State ) { UINT8 i; UINT8 j; UINT8 Freq; UINT32 Temp; UINT32 CbPcbFreqLimit; UINT8 CbPcbABDownstreamWidth; UINT8 CbPcbBAUpstreamWidth; for (i = 0; i < (State->TotalLinks * 2); i += 2) { CbPcbFreqLimit = HT_FREQUENCY_NO_LIMIT; CbPcbABDownstreamWidth = HT_WIDTH_16_BITS; CbPcbBAUpstreamWidth = HT_WIDTH_16_BITS; if (((*State->PortList)[i].Type == PORTLIST_TYPE_CPU) && ((*State->PortList)[i + 1].Type == PORTLIST_TYPE_CPU)) { State->HtInterface->GetCpu2CpuPcbLimits ((*State->PortList)[i].NodeID, (*State->PortList)[i].Link, (*State->PortList)[i + 1].NodeID, (*State->PortList)[i + 1].Link, &CbPcbABDownstreamWidth, &CbPcbBAUpstreamWidth, &CbPcbFreqLimit, State ); } else { State->HtInterface->GetIoPcbLimits ((*State->PortList)[i + 1].NodeID, (*State->PortList)[i + 1].HostLink, (*State->PortList)[i + 1].HostDepth, &CbPcbABDownstreamWidth, &CbPcbBAUpstreamWidth, &CbPcbFreqLimit, State ); } Temp = (*State->PortList)[i].PrvFrequencyCap; Temp &= (*State->PortList)[i + 1].PrvFrequencyCap; Temp &= CbPcbFreqLimit; (*State->PortList)[i].CompositeFrequencyCap = (UINT32)Temp; (*State->PortList)[i + 1].CompositeFrequencyCap = (UINT32)Temp; ASSERT (Temp != 0); Freq = LibAmdBitScanReverse (Temp); (*State->PortList)[i].SelFrequency = Freq; (*State->PortList)[i + 1].SelFrequency = Freq; Temp = (*State->PortList)[i].PrvWidthOutCap; if ((*State->PortList)[i + 1].PrvWidthInCap < Temp) { Temp = (*State->PortList)[i + 1].PrvWidthInCap; } if (CbPcbABDownstreamWidth < Temp) { Temp = CbPcbABDownstreamWidth; } (*State->PortList)[i].SelWidthOut = (UINT8)Temp; (*State->PortList)[i + 1].SelWidthIn = (UINT8)Temp; Temp = (*State->PortList)[i].PrvWidthInCap; if ((*State->PortList)[i + 1].PrvWidthOutCap < Temp) { Temp = (*State->PortList)[i + 1].PrvWidthOutCap; } if (CbPcbBAUpstreamWidth < Temp) { Temp = CbPcbBAUpstreamWidth; } (*State->PortList)[i].SelWidthIn = (UINT8)Temp; (*State->PortList)[i + 1].SelWidthOut = (UINT8)Temp; } // Calculate unit id clumping // // Find the root of each IO Chain, process the chain for clumping support. // The root is always the first link of the chain in the port list. // Clumping is not device link specific, so we can just look at the upstream ports (j+1). Use ASSERTs to sanity // check the downstream ports (j). If any device on the chain does not support clumping, the entire chain will be // disabled for clumping. // After analyzing the clumping support on the chain the CPU's portlist has the enable mask. Update all the // IO Devices on the chain with the enable mask. If any device's only have passive support, that is already enabled. // if (State->IsUsingUnitIdClumping) { for (i = 0; i < (State->TotalLinks * 2); i += 2) { if (((*State->PortList)[i].Type == PORTLIST_TYPE_CPU) && ((*State->PortList)[i + 1].Type == PORTLIST_TYPE_IO)) { (*State->PortList)[i].ClumpingSupport = HT_CLUMPING_DISABLE; if ((*State->PortList)[i + 1].ClumpingSupport != HT_CLUMPING_DISABLE) { (*State->PortList)[i].ClumpingSupport |= (*State->PortList)[i + 1].ClumpingSupport; for (j = i + 2; j < (State->TotalLinks * 2); j += 2) { if (((*State->PortList)[j].Type == PORTLIST_TYPE_IO) && ((*State->PortList)[j + 1].Type == PORTLIST_TYPE_IO)) { if (((*State->PortList)[i].NodeID == (*State->PortList)[j + 1].NodeID) && ((*State->PortList)[i].Link == (*State->PortList)[j + 1].HostLink)) { ASSERT (((*State->PortList)[i].NodeID == (*State->PortList)[j + 1].NodeID) && ((*State->PortList)[i].Link == (*State->PortList)[j].HostLink)); if ((*State->PortList)[j + 1].ClumpingSupport != HT_CLUMPING_DISABLE) { ASSERT ((((*State->PortList)[j + 1].ClumpingSupport & HT_CLUMPING_PASSIVE) == 0) || (((*State->PortList)[j + 1].ClumpingSupport & ~(HT_CLUMPING_PASSIVE)) == 0)); (*State->PortList)[i].ClumpingSupport |= (*State->PortList)[j + 1].ClumpingSupport; } else { (*State->PortList)[i].ClumpingSupport = HT_CLUMPING_DISABLE; break; } } } } if ((*State->PortList)[i + 1].ClumpingSupport != HT_CLUMPING_PASSIVE) { (*State->PortList)[i + 1].ClumpingSupport = (*State->PortList)[i].ClumpingSupport; } for (j = i + 2; j < (State->TotalLinks * 2); j += 2) { if (((*State->PortList)[j].Type == PORTLIST_TYPE_IO) && ((*State->PortList)[j + 1].Type == PORTLIST_TYPE_IO)) { if (((*State->PortList)[i].NodeID == (*State->PortList)[j + 1].NodeID) && ((*State->PortList)[i].Link == (*State->PortList)[j + 1].HostLink)) { if ((*State->PortList)[j + 1].ClumpingSupport != HT_CLUMPING_PASSIVE) { (*State->PortList)[j + 1].ClumpingSupport = (*State->PortList)[i].ClumpingSupport; // The downstream isn't really passive, just mark it so in order to write the device only once. (*State->PortList)[j].ClumpingSupport = HT_CLUMPING_PASSIVE; } } } } } } } } }
/** * Iterate through all Links, checking the frequency of each subLink pair. * * @HtFeatMethod{::F_SUBLINK_RATIO_FIXUP} * * Make the adjustment to the port list data so that the frequencies * are at a valid ratio, reducing frequency as needed to achieve * this. (All Links support the minimum 200 MHz frequency.) Repeat * the above until no adjustments are needed. * @note no hardware state changes in this routine. * * @param[in,out] State Link state and port list * */ VOID SubLinkRatioFixup ( IN OUT STATE_DATA *State ) { UINT8 i; UINT8 j; UINT8 ValidRatioItem; BOOLEAN Changes; BOOLEAN Downgrade; UINT8 HiIndex; UINT8 HiFreq; UINT8 LoFreq; UINT32 Temp; do { Changes = FALSE; for (i = 0; i < State->TotalLinks*2; i++) { // Must be a CPU Link if ((*State->PortList)[i].Type != PORTLIST_TYPE_CPU) { continue; } // Only look for subLink1's if ((*State->PortList)[i].Link < 4) { continue; } for (j = 0; j < State->TotalLinks*2; j++) { // Step 1. Find the matching subLink0 if ((*State->PortList)[j].Type != PORTLIST_TYPE_CPU) { continue; } if ((*State->PortList)[j].NodeID != (*State->PortList)[i].NodeID) { continue; } if ((*State->PortList)[j].Link != ((*State->PortList)[i].Link & 0x03)) { continue; } // Step 2. Check for an illegal frequency ratio if ((*State->PortList)[i].SelFrequency >= (*State->PortList)[j].SelFrequency) { HiIndex = i; HiFreq = (*State->PortList)[i].SelFrequency; LoFreq = (*State->PortList)[j].SelFrequency; } else { HiIndex = j; HiFreq = (*State->PortList)[j].SelFrequency; LoFreq = (*State->PortList)[i].SelFrequency; } // The frequencies are 1:1, no need to do anything if (HiFreq == LoFreq) { break; } Downgrade = TRUE; for (ValidRatioItem = 0; ValidRatioItem < (sizeof (ValidRatioList) / sizeof (VALID_RATIO_ITEM)); ValidRatioItem++) { if ((HiFreq == ValidRatioList[ValidRatioItem].HiFreq) && (LoFreq == ValidRatioList[ValidRatioItem].LoFreq)) { Downgrade = FALSE; break; } } // Step 3. Downgrade the higher of the two frequencies, and set Changes to FALSE if (Downgrade) { // Although the problem was with the port specified by hiIndex, we need to // Downgrade both ends of the Link. HiIndex = HiIndex & 0xFE; // Select the 'upstream' (i.e. even) port Temp = (*State->PortList)[HiIndex].CompositeFrequencyCap; // Remove HiFreq from the list of valid frequencies Temp = Temp & ~((UINT32)1 << HiFreq); ASSERT (Temp != 0); (*State->PortList)[HiIndex].CompositeFrequencyCap = (UINT32)Temp; (*State->PortList)[HiIndex + 1].CompositeFrequencyCap = (UINT32)Temp; HiFreq = LibAmdBitScanReverse (Temp); (*State->PortList)[HiIndex].SelFrequency = HiFreq; (*State->PortList)[HiIndex + 1].SelFrequency = HiFreq; Changes = TRUE; } } } } while (Changes); // Repeat until a valid configuration is reached }
BOOLEAN MemFOnlineSpare ( IN OUT MEM_NB_BLOCK *NBPtr ) { UINT8 Dct; UINT8 q; UINT8 Value8; BOOLEAN Flag; BOOLEAN OnlineSprEnabled[MAX_CHANNELS_PER_SOCKET]; MEM_PARAMETER_STRUCT *RefPtr; DIE_STRUCT *MCTPtr; ASSERT (NBPtr != NULL); RefPtr = NBPtr->RefPtr; Flag = FALSE; if (RefPtr->EnableOnLineSpareCtl != 0) { RefPtr->GStatus[GsbEnDIMMSpareNW] = TRUE; MCTPtr = NBPtr->MCTPtr; // Check if online spare can be enabled on current node for (Dct = 0; Dct < NBPtr->DctCount; Dct++) { ASSERT (Dct < sizeof (OnlineSprEnabled)); NBPtr->SwitchDCT (NBPtr, Dct); OnlineSprEnabled[Dct] = FALSE; if ((MCTPtr->GangedMode == 0) || (MCTPtr->Dct == 0)) { if (NBPtr->DCTPtr->Timings.DctMemSize != 0) { // Make sure at least two chip-selects are available Value8 = LibAmdBitScanReverse (NBPtr->DCTPtr->Timings.CsEnabled); if (Value8 > LibAmdBitScanForward (NBPtr->DCTPtr->Timings.CsEnabled)) { OnlineSprEnabled[Dct] = TRUE; Flag = TRUE; } else { PutEventLog (AGESA_ERROR, MEM_ERROR_DIMM_SPARING_NOT_ENABLED, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader); MCTPtr->ErrStatus[EsbSpareDis] = TRUE; } } } } // If we don't have spared rank on any DCT, we don't run the rest part of the code. if (!Flag) { return FALSE; } MCTPtr->NodeMemSize = 0; for (Dct = 0; Dct < NBPtr->DctCount; Dct++) { NBPtr->SwitchDCT (NBPtr, Dct); if (OnlineSprEnabled[Dct]) { // Only run StitchMemory if we need to set a spare rank. NBPtr->DCTPtr->Timings.DctMemSize = 0; for (q = 0; q < MAX_CS_PER_CHANNEL; q++) { NBPtr->SetBitField (NBPtr, BFCSBaseAddr0Reg + q, 0); } Flag = NBPtr->StitchMemory (NBPtr); ASSERT (Flag == TRUE); } else if ((MCTPtr->GangedMode == 0) && (NBPtr->DCTPtr->Timings.DctMemSize != 0)) { // Otherwise, need to adjust the memory size on the node. MCTPtr->NodeMemSize += NBPtr->DCTPtr->Timings.DctMemSize; MCTPtr->NodeSysLimit = MCTPtr->NodeMemSize - 1; } } return TRUE; } else { return FALSE; } }