| /* $NoKeywords:$ */ |
| /** |
| * @file |
| * |
| * mn.c |
| * |
| * Common Northbridge functions |
| * |
| * @xrefitem bom "File Content Label" "Release Content" |
| * @e project: AGESA |
| * @e sub-project: (Mem/NB/) |
| * @e \$Revision: 35136 $ @e \$Date: 2010-07-16 11:29:48 +0800 (Fri, 16 Jul 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 "AdvancedApi.h" |
| #include "amdlib.h" |
| #include "Ids.h" |
| #include "mport.h" |
| #include "OptionMemory.h" |
| #include "mm.h" |
| #include "mn.h" |
| #include "mu.h" |
| #include "Filecode.h" |
| CODE_GROUP (G1_PEICC) |
| RDATA_GROUP (G1_PEICC) |
| |
| #define FILECODE PROC_MEM_NB_MN_FILECODE |
| |
| |
| /*---------------------------------------------------------------------------- |
| * DEFINITIONS AND MACROS |
| * |
| *---------------------------------------------------------------------------- |
| */ |
| /*---------------------------------------------------------------------------- |
| * TYPEDEFS AND STRUCTURES |
| * |
| *---------------------------------------------------------------------------- |
| */ |
| |
| /*---------------------------------------------------------------------------- |
| * PROTOTYPES OF LOCAL FUNCTIONS |
| * |
| *---------------------------------------------------------------------------- |
| */ |
| BOOLEAN |
| STATIC |
| MemNDefaultFamilyHookNb ( |
| IN OUT MEM_NB_BLOCK *NBPtr, |
| IN OUT VOID *OptParam |
| ); |
| |
| /*---------------------------------------------------------------------------- |
| * EXPORTED FUNCTIONS |
| * |
| *---------------------------------------------------------------------------- |
| */ |
| extern OPTION_MEM_FEATURE_NB* memNTrainFlowControl[]; |
| |
| extern BUILD_OPT_CFG UserOptions; |
| |
| /* -----------------------------------------------------------------------------*/ |
| /** |
| * |
| * This function initializes member functions and variables of NB block. |
| * |
| * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK |
| * |
| */ |
| |
| VOID |
| MemNInitNBDataNb ( |
| IN OUT MEM_NB_BLOCK *NBPtr |
| ) |
| { |
| INT32 i; |
| UINT8 *BytePtr; |
| |
| NBPtr->DctCachePtr = NBPtr->DctCache; |
| NBPtr->PsPtr = NBPtr->PSBlock; |
| |
| BytePtr = (UINT8 *) (NBPtr->DctCache); |
| for (i = 0; i < sizeof (NBPtr->DctCache); i++) { |
| *BytePtr++ = 0; |
| } |
| |
| for (i = 0; i < EnumSize; i++) { |
| NBPtr->IsSupported[i] = FALSE; |
| } |
| |
| for (i = 0; i < NumberOfHooks; i++) { |
| NBPtr->FamilySpecificHook[i] = MemNDefaultFamilyHookNb; |
| } |
| |
| NBPtr->SwitchDCT = MemNSwitchDCTNb; |
| NBPtr->SwitchChannel = MemNSwitchChannelNb; |
| NBPtr->GetBitField = MemNGetBitFieldNb; |
| NBPtr->SetBitField = MemNSetBitFieldNb; |
| } |
| |
| /* -----------------------------------------------------------------------------*/ |
| /** |
| * |
| * |
| * Get System address of Chipselect RJ 16 bits (Addr[47:16]) |
| * |
| * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK |
| * @param[in] Receiver - Chipselect to be targeted [0-7] |
| * @param[out] AddrPtr - Pointer to System Address [47:16] |
| * |
| * @return TRUE - Address is valid |
| * @return FALSE - Address is not valid |
| */ |
| |
| BOOLEAN |
| MemNGetMCTSysAddrNb ( |
| IN OUT MEM_NB_BLOCK *NBPtr, |
| IN UINT8 Receiver, |
| OUT UINT32 *AddrPtr |
| ) |
| { |
| S_UINT64 SMsr; |
| UINT32 CSBase; |
| UINT32 HoleBase; |
| UINT32 DctSelBaseAddr; |
| UINT32 BottomUma; |
| DIE_STRUCT *MCTPtr; |
| MEM_DATA_STRUCT *MemPtr; |
| |
| MCTPtr = NBPtr->MCTPtr; |
| MemPtr = NBPtr->MemPtr; |
| |
| ASSERT (Receiver < 8); |
| |
| CSBase = MemNGetBitFieldNb (NBPtr, BFCSBaseAddr0Reg + Receiver); |
| if (CSBase & 1) { |
| ASSERT ((CSBase & 0xE0) == 0); // Should not enable CS interleaving before DQS training. |
| |
| // Scale base address from [39:8] to [47:16] |
| CSBase >>= 8; |
| |
| HoleBase = MCTPtr->NodeHoleBase ? MCTPtr->NodeHoleBase : 0x7FFFFFFF; |
| |
| if ((MemNGetBitFieldNb (NBPtr, BFDctSelHiRngEn) == 1) && (NBPtr->Dct == MemNGetBitFieldNb (NBPtr, BFDctSelHi))) { |
| DctSelBaseAddr = MemNGetBitFieldNb (NBPtr, BFDctSelBaseAddr) << (27 - 16); |
| if (DctSelBaseAddr > HoleBase) { |
| DctSelBaseAddr -= _4GB_RJ16 - HoleBase; |
| } |
| CSBase += DctSelBaseAddr; |
| } else { |
| CSBase += MCTPtr->NodeSysBase; |
| } |
| |
| if (CSBase >= HoleBase) { |
| CSBase += _4GB_RJ16 - HoleBase; |
| } |
| |
| CSBase += (UINT32)1 << (21 - 16); // Add 2MB offset to avoid compat area. |
| if ((CSBase >= (MCT_TRNG_KEEPOUT_START >> 8)) && (CSBase <= (MCT_TRNG_KEEPOUT_END >> 8))) { |
| CSBase += (((MCT_TRNG_KEEPOUT_END >> 8) - CSBase) + 0x0F) & 0xFFFFFFF0; |
| } |
| |
| if (MCTPtr->Status[SbHWHole]) { |
| if (MCTPtr->Status[SbSWNodeHole]) { |
| LibAmdMsrRead (TOP_MEM, (UINT64 *)&SMsr, &MemPtr->StdHeader); |
| |
| if ((CSBase >= (SMsr.lo >> 16)) && (CSBase < _4GB_RJ16)) { |
| return FALSE; |
| } |
| } |
| } |
| |
| BottomUma = NBPtr->RefPtr->Sub4GCacheTop >> 16; |
| if (BottomUma && (CSBase >= BottomUma) && (CSBase < _4GB_RJ16)) { |
| return FALSE; |
| } |
| *AddrPtr = CSBase; |
| return TRUE; |
| } |
| return FALSE; |
| } |
| |
| /* -----------------------------------------------------------------------------*/ |
| /** |
| * |
| * This function determines if a Rank is enabled. |
| * |
| * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK |
| * @param[in] Receiver - Receiver to check |
| * @return - FALSE |
| * |
| */ |
| |
| BOOLEAN |
| MemNRankEnabledNb ( |
| IN OUT MEM_NB_BLOCK *NBPtr, |
| IN UINT8 Receiver |
| ) |
| { |
| UINT32 CSBase; |
| CSBase = MemNGetBitFieldNb (NBPtr, BFCSBaseAddr0Reg + Receiver); |
| if (CSBase & 1) { |
| return TRUE; |
| } else { |
| return FALSE; |
| } |
| } |
| |
| /* -----------------------------------------------------------------------------*/ |
| /** |
| * |
| * |
| * This function sets the EccSymbolSize bit depending upon configurations |
| * and system override. |
| * |
| * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK |
| * |
| */ |
| |
| VOID |
| MemNSetEccSymbolSizeNb ( |
| IN OUT MEM_NB_BLOCK *NBPtr |
| ) |
| { |
| UINT16 X4DimmsOnly; |
| BOOLEAN Size; |
| DIE_STRUCT *MCTPtr; |
| DCT_STRUCT *DCTPtr; |
| |
| ASSERT (NBPtr != NULL); |
| |
| MCTPtr = NBPtr->MCTPtr; |
| DCTPtr = NBPtr->DCTPtr; |
| |
| // Determine if this node has only x4 DRAM parts |
| X4DimmsOnly = (UINT16) ((!(DCTPtr->Timings.Dimmx8Present | DCTPtr->Timings.Dimmx16Present)) && DCTPtr->Timings.Dimmx4Present); |
| // |
| // Check if EccSymbolSize BKDG value is overridden |
| // |
| if (UserOptions.CfgEccSymbolSize != ECCSYMBOLSIZE_USE_BKDG) { |
| Size = (UserOptions.CfgEccSymbolSize == ECCSYMBOLSIZE_FORCE_X4) ? FALSE : TRUE; |
| } else { |
| if (X4DimmsOnly && MCTPtr->GangedMode) { |
| Size = FALSE; |
| } else { |
| Size = TRUE; |
| } |
| } |
| IDS_OPTION_HOOK (IDS_ECCSYMBOLSIZE, &Size, &(NBPtr->MemPtr->StdHeader)); |
| MemNSetBitFieldNb (NBPtr, BFEccSymbolSize, (UINT32) Size); |
| } |
| |
| /* -----------------------------------------------------------------------------*/ |
| /** |
| * |
| * This function sets the training control flow |
| * The DDR3 mode bit must be set prior to calling this function |
| * |
| * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK |
| */ |
| BOOLEAN |
| MemNTrainingFlowNb ( |
| IN OUT MEM_NB_BLOCK *NBPtr |
| ) |
| { |
| if (MemNGetBitFieldNb (NBPtr, BFDdr3Mode)!= 0) { |
| memNTrainFlowControl[DDR3_TRAIN_FLOW] (NBPtr); |
| } else { |
| memNTrainFlowControl[DDR2_TRAIN_FLOW] (NBPtr); |
| } |
| return TRUE; |
| } |
| |
| /*-----------------------------------------------------------------------------*/ |
| /** |
| * |
| * This function flushes the training pattern |
| * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK |
| * @param[in] Address - System Address [47:16] |
| * @param[in] ClCount - Number of cache lines |
| * |
| */ |
| |
| VOID |
| MemNFlushPatternNb ( |
| IN OUT MEM_NB_BLOCK *NBPtr, |
| IN UINT32 Address, |
| IN UINT16 ClCount |
| ) |
| { |
| // Due to speculative execution during MemUReadCachelines, we must |
| // flush one more cache line than we read. |
| MemUProcIOClFlush (Address, ClCount + 1, NBPtr->MemPtr); |
| } |
| |
| /* -----------------------------------------------------------------------------*/ |
| /** |
| * |
| * This function compares test pattern with data in buffer and |
| * return a pass/fail bitmap for 8 bytelanes (upper 8 bits are reserved) |
| * |
| * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK |
| * @param[in] Buffer[] - Buffer data from DRAM (Measured data from DRAM) to compare |
| * @param[in] Pattern[] - Pattern (Expected data in ROM/CACHE) to compare against |
| * @param[in] ByteCount - Byte count |
| * |
| * @return PASS - Bitmap of results of comparison |
| */ |
| |
| UINT16 |
| MemNCompareTestPatternNb ( |
| IN OUT MEM_NB_BLOCK *NBPtr, |
| IN UINT8 Buffer[], |
| IN UINT8 Pattern[], |
| IN UINT16 ByteCount |
| ) |
| { |
| UINT16 i; |
| UINT16 Pass; |
| UINT8 ColumnCount; |
| UINT8 FailingBitMask[8]; |
| |
| ASSERT ((ByteCount == 18 * 64) || (ByteCount == 9 * 64) || (ByteCount == 64 * 64) || (ByteCount == 32 * 64) || (ByteCount == 3 * 64)); |
| |
| ColumnCount = NBPtr->ChannelPtr->ColumnCount; |
| Pass = 0xFFFF; |
| // |
| // Clear Failing Bit Mask |
| // |
| for (i = 0; i < sizeof (FailingBitMask); i++) { |
| FailingBitMask[i] = 0; |
| } |
| |
| if (NBPtr->Ganged && (NBPtr->Dct != 0)) { |
| i = 8; // DCT 1 in ganged mode |
| } else { |
| i = 0; |
| } |
| |
| for (; i < ByteCount; i++) { |
| if (Buffer[i] != Pattern[i]) { |
| // if bytelane n fails |
| Pass &= ~((UINT16)1 << (i % 8)); // clear bit n |
| FailingBitMask[i % NBPtr->TechPtr->MaxByteLanes ()] |= (Buffer[i] ^ Pattern[i]); |
| } |
| |
| if (NBPtr->Ganged && ((i & 7) == 7)) { |
| i += 8; // if ganged, skip over other Channel's Data |
| } |
| } |
| // |
| // Accumulate Failing bit data |
| // |
| for (i = 0; i < sizeof (FailingBitMask); i++) { |
| NBPtr->ChannelPtr->FailingBitMask[(ColumnCount * NBPtr->TechPtr->ChipSel) + i] &= |
| FailingBitMask[i]; |
| } |
| |
| return Pass; |
| } |
| |
| /*----------------------------------------------------------------------------- |
| * |
| * |
| * This function compares test pattern with data in buffer and |
| * return a pass/fail bitmap for 8 bytelanes (upper 8 bits are reserved) |
| * |
| * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK |
| * @param[in] Buffer[] - Buffer data from DRAM (Measured data from DRAM) to compare |
| * @param[in] Pattern[] - Pattern (Expected data in ROM/CACHE) to compare against |
| * @param[in] ByteCount - Byte count |
| * |
| * @retval PASS - Bitmap of results of comparison |
| * ---------------------------------------------------------------------------- |
| */ |
| UINT16 |
| MemNInsDlyCompareTestPatternNb ( |
| IN MEM_NB_BLOCK *NBPtr, |
| IN UINT8 Buffer[], |
| IN UINT8 Pattern[], |
| IN UINT16 ByteCount |
| ) |
| { |
| UINT16 i; |
| UINT16 Pass; |
| UINT16 BeatOffset; |
| UINT16 BeatCnt; |
| UINT8 ColumnCount; |
| UINT8 FailingBitMask[8]; |
| |
| ASSERT ((ByteCount == 18 * 64) || (ByteCount == 9 * 64) || (ByteCount == 64 * 64) || (ByteCount == 32 * 64) || (ByteCount == 3 * 64)); |
| |
| ColumnCount = NBPtr->ChannelPtr->ColumnCount; |
| Pass = 0xFFFF; |
| // |
| // Clear Failing Bit Mask |
| // |
| for (i = 0; i < sizeof (FailingBitMask); i++) { |
| FailingBitMask[i] = 0; |
| } |
| |
| if (NBPtr->Ganged && (NBPtr->Dct != 0)) { |
| i = 8; // DCT 1 in ganged mode |
| } else { |
| i = 0; |
| } |
| |
| if (NBPtr->Ganged) { |
| BeatOffset = 16; |
| } else { |
| BeatOffset = 8; |
| } |
| |
| BeatCnt = 0; |
| for (; i < ByteCount; i++) { |
| |
| if (Buffer[i] != Pattern[i + BeatOffset]) { |
| // if bytelane n fails |
| Pass &= ~((UINT16)1 << (i % 8)); // clear bit n |
| FailingBitMask[i % NBPtr->TechPtr->MaxByteLanes ()] |= (Buffer[i] ^ Pattern[i + BeatOffset]); |
| } |
| |
| if ((i & 7) == 7) { |
| if (NBPtr->Ganged) { |
| i += 8; // if ganged, skip over other Channel's Data |
| } |
| BeatCnt++; |
| } |
| |
| if ((BeatCnt & 3) == 3) { |
| // Skip last data beat of a 4-beat burst. |
| BeatCnt++; |
| i = i + BeatOffset; |
| } |
| } |
| // |
| // Accumulate Failing bit data |
| // |
| for (i = 0; i < sizeof (FailingBitMask); i++) { |
| NBPtr->ChannelPtr->FailingBitMask[(ColumnCount * NBPtr->TechPtr->ChipSel) + i] &= |
| FailingBitMask[i]; |
| } |
| |
| return Pass; |
| } |
| |
| /* -----------------------------------------------------------------------------*/ |
| /** |
| * |
| * This function sets the training control flow for UNB |
| * The DDR3 mode bit must be set prior to calling this function |
| * |
| * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK |
| */ |
| BOOLEAN |
| MemNTrainingFlowUnb ( |
| IN OUT MEM_NB_BLOCK *NBPtr |
| ) |
| { |
| memNTrainFlowControl[DDR3_TRAIN_FLOW] (NBPtr); |
| return TRUE; |
| } |
| /*---------------------------------------------------------------------------- |
| * LOCAL FUNCTIONS |
| * |
| *---------------------------------------------------------------------------- |
| */ |
| |
| /*----------------------------------------------------------------------------- |
| * |
| * |
| * This function is an empty function used to intialize FamilySpecificHook array |
| * |
| * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK |
| * @param[in,out] OptParam - Optional parameter |
| * |
| * @return TRUE - always |
| * ---------------------------------------------------------------------------- |
| */ |
| BOOLEAN |
| STATIC |
| MemNDefaultFamilyHookNb ( |
| IN OUT MEM_NB_BLOCK *NBPtr, |
| IN OUT VOID *OptParam |
| ) |
| { |
| return TRUE; |
| } |