/* $NoKeywords:$ */ /** * @file * * mndcton.c * * Northbridge ON DCT supporting functions * * @xrefitem bom "File Content Label" "Release Content" * @e project: AGESA * @e sub-project: (Mem/NB/ON) * @e \$Revision: 37169 $ @e \$Date: 2010-09-01 05:35:27 +0800 (Wed, 01 Sep 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 "Ids.h" #include "mm.h" #include "mn.h" #include "mt.h" #include "mu.h" #include "OptionMemory.h" // need def for MEM_FEAT_BLOCK_NB #include "mnon.h" #include "merrhdl.h" #include "GeneralServices.h" #include "cpuFamilyTranslation.h" #include "cpuCommonF14Utilities.h" #include "Filecode.h" #define FILECODE PROC_MEM_NB_ON_MNDCTON_FILECODE /*---------------------------------------------------------------------------- * DEFINITIONS AND MACROS * *---------------------------------------------------------------------------- */ #define UNUSED_CLK 4 #define MAX_RD_DQS_DLY 0x1F /*---------------------------------------------------------------------------- * TYPEDEFS AND STRUCTURES * *---------------------------------------------------------------------------- */ /*---------------------------------------------------------------------------- * PROTOTYPES OF LOCAL FUNCTIONS * *---------------------------------------------------------------------------- */ /*---------------------------------------------------------------------------- * EXPORTED FUNCTIONS * *---------------------------------------------------------------------------- */ extern BUILD_OPT_CFG UserOptions; /* -----------------------------------------------------------------------------*/ /** * * * This function programs the memory controller with configuration parameters * * * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK * * @return TRUE - An Error value lower than AGESA_FATAL may have occurred * @return FALSE - An Error value greater than or equal to AGESA_FATAL may have occurred * @return NBPtr->MCTPtr->ErrCode - Contains detailed AGESA_STATUS value */ BOOLEAN MemNAutoConfigON ( IN OUT MEM_NB_BLOCK *NBPtr ) { DIE_STRUCT *MCTPtr; DCT_STRUCT *DCTPtr; UINT8 PowerDownMode; MCTPtr = NBPtr->MCTPtr; DCTPtr = NBPtr->DCTPtr; //====================================================================== // Build Dram Control Register Value (F2x78) //====================================================================== // //====================================================================== // Build Dram Config Lo Register Value //====================================================================== // MemNSetBitFieldNb (NBPtr, BFEnDispAutoPrecharge, 1); MemNSetBitFieldNb (NBPtr, BFIdleCycInit, 3); //====================================================================== // Build Dram Config Hi Register Value //====================================================================== // MemNSetBitFieldNb (NBPtr, BFMemClkFreq, MemNGetMemClkFreqIdClientNb (NBPtr, DCTPtr->Timings.Speed)); PowerDownMode = (UINT8) ((UserOptions.CfgPowerDownMode == POWER_DOWN_MODE_AUTO) ? POWER_DOWN_BY_CHIP_SELECT : UserOptions.CfgPowerDownMode); PowerDownMode = (!NBPtr->IsSupported[ChannelPDMode]) ? PowerDownMode : 0; IDS_OPTION_HOOK (IDS_POWERDOWN_MODE, &PowerDownMode, &(NBPtr->MemPtr->StdHeader)); if (PowerDownMode == 1) { MemNSetBitFieldNb (NBPtr, BFPowerDownMode, 1); } MemNSetBitFieldNb (NBPtr, BFPchgPDModeSel, 1); MemNSetBitFieldNb (NBPtr, BFDcqBypassMax, 0xE); MemNSetBitFieldNb (NBPtr, BFDctSelBankSwap, 1); //====================================================================== // Build Dram Config Misc Register Value //====================================================================== // // Max out Non-SPD timings MemNSetBitFieldNb (NBPtr, BFNonSPD, 0x18FF); MemNSetBitFieldNb (NBPtr, BFNonSPDHi, 0x2A); MemNSetBitFieldNb (NBPtr, BFTwrrdSD, 0xA); MemNSetBitFieldNb (NBPtr, BFTrdrdSD, 0x8); MemNSetBitFieldNb (NBPtr, BFTwrwrSD, 0x9); MemNSetBitFieldNb (NBPtr, BFWrOdtOnDuration, DEFAULT_WR_ODT_ON_ON); MemNSetBitFieldNb (NBPtr, BFRdOdtOnDuration, DEFAULT_RD_ODT_ON_ON); MemNSetBitFieldNb (NBPtr, BFWrOdtTrnOnDly, 0); //====================================================================== // DRAM MRS Register, set ODT //====================================================================== MemNSetBitFieldNb (NBPtr, BFBurstCtrl, 1); // DrvImpCtrl: drive impedance control.01b(34 ohm driver; Ron34 = Rzq/7) MemNSetBitFieldNb (NBPtr, BFDrvImpCtrl, 1); return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL); } /*---------------------------------------------------------------------------- * LOCAL FUNCTIONS * *---------------------------------------------------------------------------- */ /* -----------------------------------------------------------------------------*/ /** * * This function sends an MRS command * * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK * */ VOID MemNSendMrsCmdON ( IN OUT MEM_NB_BLOCK *NBPtr ) { MemNSetASRSRTNb (NBPtr); MemNSwapBitsNb (NBPtr); IDS_HDT_CONSOLE (MEM_FLOW, "\t\t\tCS%d MR%d %04x\n", (MemNGetBitFieldNb (NBPtr, BFDramInitRegReg) >> 20) & 0xF, (MemNGetBitFieldNb (NBPtr, BFDramInitRegReg) >> 16) & 0xF, (MemNGetBitFieldNb (NBPtr, BFDramInitRegReg) & 0xFFFF)); // 1.Set SendMrsCmd=1 MemNSetBitFieldNb (NBPtr, BFSendMrsCmd, 1); // 2.Wait for SendMrsCmd=0 MemNPollBitFieldNb (NBPtr, BFSendMrsCmd, 0, PCI_ACCESS_TIMEOUT, FALSE); } /* -----------------------------------------------------------------------------*/ /** * * * This function combines all the memory into a contiguous map. * Requires that Mask values for each bank be programmed first and that * the chip-select population indicator is correctly set. * * * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK * * @return TRUE - An Error value lower than AGESA_FATAL may have occurred * @return FALSE - An Error value greater than or equal to AGESA_FATAL may have occurred */ BOOLEAN MemNStitchMemoryON ( IN OUT MEM_NB_BLOCK *NBPtr ) { UINT32 NxtCSBase; UINT32 CurCSBase; UINT32 CsSize; UINT32 BiggestBank; UINT8 p; UINT8 q; UINT8 BiggestDimm; DIE_STRUCT *MCTPtr; DCT_STRUCT *DCTPtr; MCTPtr = NBPtr->MCTPtr; DCTPtr = NBPtr->DCTPtr; DCTPtr->Timings.CsEnabled = 0; NxtCSBase = 0; for (p = 0; p < MAX_CS_PER_CHANNEL_ON; p++) { BiggestBank = 0; BiggestDimm = 0; for (q = 0; q < MAX_CS_PER_CHANNEL_ON; q++) { if (((DCTPtr->Timings.CsPresent & ~DCTPtr->Timings.CsTestFail) & ((UINT16)1 << q)) != 0) { if ((MemNGetBitFieldNb (NBPtr, BFCSBaseAddr0Reg + q) & 7) == 0) { // (CSEnable|Spare==1)bank is not enabled yet CsSize = MemNGetBitFieldNb (NBPtr, BFCSMask0Reg + (q >> 1)); if (CsSize != 0) { CsSize += ((UINT32)1 << 19); CsSize &= 0xFFF80000; } if (CsSize > BiggestBank) { BiggestBank = CsSize; BiggestDimm = q; } } } } if (BiggestBank != 0) { CurCSBase = NxtCSBase; CurCSBase |= ((UINT32)1 << BFCSEnable); NxtCSBase += BiggestBank; if ((BiggestDimm & 1) != 0) { if ((DCTPtr->Timings.DimmMirrorPresent & (1 << (BiggestDimm >> 1))) != 0) { CurCSBase |= ((UINT32)1 << BFOnDimmMirror); } } MemNSetBitFieldNb (NBPtr, BFCSBaseAddr0Reg + BiggestDimm, CurCSBase); DCTPtr->Timings.CsEnabled |= (1 << BiggestDimm); } if ((DCTPtr->Timings.CsTestFail & ((UINT16)1 << p)) != 0) { MemNSetBitFieldNb (NBPtr, (BFCSBaseAddr0Reg + p), (UINT32)1 << BFTestFail); } } if (NxtCSBase != 0) { DCTPtr->Timings.DctMemSize = NxtCSBase >> 8; // Scale base address from [39:8] to [47:16] NBPtr->MCTPtr->NodeMemSize += NBPtr->DCTPtr->Timings.DctMemSize; NBPtr->MCTPtr->NodeSysLimit = NBPtr->MCTPtr->NodeMemSize - 1; } else { PutEventLog (AGESA_FATAL, MEM_ERROR_NO_DIMM_FOUND_ON_SYSTEM, 0, 0, 0, 0, &NBPtr->MemPtr->StdHeader); SetMemError (AGESA_FATAL, MCTPtr); } return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL); } /* -----------------------------------------------------------------------------*/ /** * * * This function sets the maximum round-trip latency in the system from the processor to the DRAM * devices and back for Ontario. * * * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK * @param[in] MaxRcvEnDly - Maximum receiver enable delay value * */ VOID MemNSetMaxLatencyON ( IN OUT MEM_NB_BLOCK *NBPtr, IN UINT16 MaxRcvEnDly ) { UINT32 N; UINT32 T; UINT32 P; UINT32 Px2; UINT32 MemClkPeriod; AGESA_TESTPOINT (TpProcMemRcvrCalcLatency, &(NBPtr->MemPtr->StdHeader)); N = 0x50; // init value for MaxRdLat used in training if (MaxRcvEnDly != 0xFFFF) { T = MemNTotalSyncComponentsClientNb (NBPtr); // P = P + CEIL(MAX (total delay in DqsRcvEn + RdDqsTime)) P = ((MaxRcvEnDly + MAX_RD_DQS_DLY) + 31) / 32; // P = P + 6.5 // T = T + 2586 ps Px2 = (P * 2) + 13; T += 2586; // N = (P/(MemClkFreq * 2) + T) * NclkFreq MemClkPeriod = 1000000 / NBPtr->DCTPtr->Timings.Speed; N = ((((Px2 * MemClkPeriod + 3) / 4) + T) * NBPtr->NBClkFreq + 999999) / 1000000; N += 2; } NBPtr->DCTPtr->Timings.MaxRdLat = (UINT16) N; ASSERT (N <= 0x3FF); IDS_HDT_CONSOLE (MEM_FLOW, "\t\tMaxRdLat: %03x\n", N); MemNSetBitFieldNb (NBPtr, BFMaxLatency, N); } /* -----------------------------------------------------------------------------*/ /** * * * This function retrieves the Max latency parameters * * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK * * @param[in] *MinDlyPtr - Pointer to variable to store the Minimum Delay value * @param[in] *MaxDlyPtr - Pointer to variable to store the Maximum Delay value * @param[in] *DlyBiasPtr - Pointer to variable to store Delay Bias value * @param[in] MaxDlyForMaxRdLat - Maximum receiver enable delay value * */ VOID MemNGetMaxLatParamsClientON ( IN OUT MEM_NB_BLOCK *NBPtr, IN UINT16 MaxDlyForMaxRdLat, IN OUT UINT16 *MinDlyPtr, IN OUT UINT16 *MaxDlyPtr, IN OUT UINT16 *DlyBiasPtr ) { UINT32 P; UINT32 Px2; UINT32 T; UINT32 MemClkPeriod; T = MemNTotalSyncComponentsClientNb (NBPtr); // P = P + CEIL(MAX (total delay in DqsRcvEn + RdDqsTime)) P = (MaxDlyForMaxRdLat + 31) / 32; // P = P + 6.5 // T = T + 2586 ps Px2 = (P * 2) + 13; T += 2586; // N = (P/(MemClkFreq * 2) + T) * NclkFreq MemClkPeriod = 1000000 / NBPtr->DCTPtr->Timings.Speed; *MinDlyPtr = (UINT16) (((((Px2 * MemClkPeriod + 3) / 4) + T) * NBPtr->NBClkFreq + 999999) / 1000000); if (NBPtr->NbFreqChgState == 1) { *MinDlyPtr += 2; } else { *MinDlyPtr += 1; } *MaxDlyPtr = 100 + *MinDlyPtr; // 100 fixed iterations // IF ((NCLK!=MEMCLK) && (NCLK!=MEMCLK/2)) // THEN TrainingOffset = 3 // ELSE TrainingOffset = 2 if ((NBPtr->NBClkFreq == NBPtr->DCTPtr->Timings.Speed) || (NBPtr->NBClkFreq == (UINT32) (NBPtr->DCTPtr->Timings.Speed / 2)) || (NBPtr->NBClkFreq == (UINT32) (NBPtr->DCTPtr->Timings.Speed / 2 + 1))) { *DlyBiasPtr = 2; } else { *DlyBiasPtr = 3; } // Register settings required before MaxRdLat training MemNSetBitFieldNb (NBPtr, BFForceCasToSlot0, 1); } /* -----------------------------------------------------------------------------*/ /** * * This function is a wrapper to call a CPU routine to change NB P-state and * update NB frequency. * * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK * @param[in] *NBPstate - NB Pstate * * @return TRUE - Succeed * @return FALSE - Fail */ BOOLEAN MemNChangeNbFrequencyWrapON ( IN OUT MEM_NB_BLOCK *NBPtr, IN UINT32 NBPstate ) { BOOLEAN Status; UINT32 NBFreq; UINT32 Memclk; CPU_SPECIFIC_SERVICES *FamilySpecificServices; if (NBPtr->NbFreqChgState == 0) { // While in state 0, report the new memclk to the // CPU module to adjust the NB P-state settings. Memclk = NBPtr->DCTPtr->Timings.Speed; } else { // We have already adjusted for target memclk. // Indicate NB P-state change only. Memclk = 0; } Status = F14NbPstateInit (Memclk, MemNGetMemClkFreqIdClientNb (NBPtr, NBPtr->DCTPtr->Timings.Speed), NBPstate, &NBFreq, &(NBPtr->MemPtr->StdHeader)); if (Status) { // When NB frequency change succeeds, TSC rate may have changed. // We need to update TSC rate GetCpuServicesOfCurrentCore (&FamilySpecificServices, &NBPtr->MemPtr->StdHeader); FamilySpecificServices->GetTscRate (FamilySpecificServices, &NBPtr->MemPtr->TscRate, &NBPtr->MemPtr->StdHeader); } return Status; } /* -----------------------------------------------------------------------------*/ /** * * This function sets Dqs Odt for ON * * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK * @param[in,out] *OptParam - Optional parameter * * @return TRUE */ BOOLEAN MemNSetDqsODTON ( IN OUT MEM_NB_BLOCK *NBPtr, IN OUT VOID *OptParam ) { if ((NBPtr->DCTPtr->Timings.Speed == DDR1333_FREQUENCY) && (NBPtr->ChannelPtr->Dimms == 1)) { MemNSetBitFieldNb (NBPtr, BFDQOdt03, 0x20); MemNSetBitFieldNb (NBPtr, BFDQOdt47, 0x20); } return TRUE; }