예제 #1
0
파일: mmLvDdr3.c 프로젝트: B-Rich/coreboot
/**
 *
 *  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;
}
예제 #2
0
/**
 * 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
    );
}
예제 #3
0
파일: mmLvDdr3.c 프로젝트: AdriDlu/coreboot
/**
 *
 *  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;
}
예제 #4
0
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;
}
예제 #5
0
/**
 * 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);
}
예제 #6
0
/**
 * 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;
                }
              }
            }
          }
        }
      }
    }
  }
}
예제 #7
0
/**
 * 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
}
예제 #8
0
파일: mfspr.c 프로젝트: Godkey/coreboot
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;
  }
}