| /* $NoKeywords:$ */ |
| /** |
| * @file |
| * |
| * mndcttn.c |
| * |
| * Northbridge DCT support for TN |
| * |
| * @xrefitem bom "File Content Label" "Release Content" |
| * @e project: AGESA |
| * @e sub-project: (Mem/NB/TN) |
| * @e \$Revision: 63661 $ @e \$Date: 2012-01-03 01:02:47 -0600 (Tue, 03 Jan 2012) $ |
| * |
| **/ |
| /***************************************************************************** |
| * |
| * Copyright 2008 - 2012 ADVANCED MICRO DEVICES, INC. All Rights Reserved. |
| * |
| * AMD is granting you permission to use this software (the Materials) |
| * pursuant to the terms and conditions of your Software License Agreement |
| * with AMD. This header does *NOT* give you permission to use the Materials |
| * or any rights under AMD's intellectual property. Your use of any portion |
| * of these Materials shall constitute your acceptance of those terms and |
| * conditions. If you do not agree to the terms and conditions of the Software |
| * License Agreement, please do not use any portion of these Materials. |
| * |
| * CONFIDENTIALITY: The Materials and all other information, identified as |
| * confidential and provided to you by AMD shall be kept confidential in |
| * accordance with the terms and conditions of the Software License Agreement. |
| * |
| * LIMITATION OF LIABILITY: THE MATERIALS AND ANY OTHER RELATED INFORMATION |
| * PROVIDED TO YOU BY AMD ARE PROVIDED "AS IS" WITHOUT ANY EXPRESS OR IMPLIED |
| * WARRANTY OF ANY KIND, INCLUDING BUT NOT LIMITED TO WARRANTIES OF |
| * MERCHANTABILITY, NONINFRINGEMENT, TITLE, FITNESS FOR ANY PARTICULAR PURPOSE, |
| * OR WARRANTIES ARISING FROM CONDUCT, COURSE OF DEALING, OR USAGE OF TRADE. |
| * IN NO EVENT SHALL AMD OR ITS LICENSORS BE LIABLE FOR ANY DAMAGES WHATSOEVER |
| * (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, BUSINESS |
| * INTERRUPTION, OR LOSS OF INFORMATION) ARISING OUT OF AMD'S NEGLIGENCE, |
| * GROSS NEGLIGENCE, THE USE OF OR INABILITY TO USE THE MATERIALS OR ANY OTHER |
| * RELATED INFORMATION PROVIDED TO YOU BY AMD, EVEN IF AMD HAS BEEN ADVISED OF |
| * THE POSSIBILITY OF SUCH DAMAGES. BECAUSE SOME JURISDICTIONS PROHIBIT THE |
| * EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, |
| * THE ABOVE LIMITATION MAY NOT APPLY TO YOU. |
| * |
| * AMD does not assume any responsibility for any errors which may appear in |
| * the Materials or any other related information provided to you by AMD, or |
| * result from use of the Materials or any related information. |
| * |
| * You agree that you will not reverse engineer or decompile the Materials. |
| * |
| * NO SUPPORT OBLIGATION: AMD is not obligated to furnish, support, or make any |
| * further information, software, technical information, know-how, or show-how |
| * available to you. Additionally, AMD retains the right to modify the |
| * Materials at any time, without notice, and is not obligated to provide such |
| * modified Materials to you. |
| * |
| * U.S. GOVERNMENT RESTRICTED RIGHTS: The Materials are provided with |
| * "RESTRICTED RIGHTS." Use, duplication, or disclosure by the Government is |
| * subject to the restrictions as set forth in FAR 52.227-14 and |
| * DFAR252.227-7013, et seq., or its successor. Use of the Materials by the |
| * Government constitutes acknowledgement of AMD's proprietary rights in them. |
| * |
| * EXPORT ASSURANCE: You agree and certify that neither the Materials, nor any |
| * direct product thereof will be exported directly or indirectly, into any |
| * country prohibited by the United States Export Administration Act and the |
| * regulations thereunder, without the required authorization from the U.S. |
| * government nor will be used for any purpose prohibited by the same. |
| * *************************************************************************** |
| * |
| */ |
| |
| |
| /* |
| *---------------------------------------------------------------------------- |
| * MODULES USED |
| * |
| *---------------------------------------------------------------------------- |
| */ |
| |
| |
| |
| #include "AGESA.h" |
| #include "amdlib.h" |
| #include "Ids.h" |
| #include "mport.h" |
| #include "mm.h" |
| #include "mn.h" |
| #include "mt.h" |
| #include "mu.h" |
| #include "OptionMemory.h" |
| #include "mntn.h" |
| #include "mftds.h" |
| #include "merrhdl.h" |
| #include "cpuFamRegisters.h" |
| #include "GeneralServices.h" |
| #include "cpuFamilyTranslation.h" |
| #include "cpuCommonF15Utilities.h" |
| #include "Filecode.h" |
| CODE_GROUP (G3_DXE) |
| RDATA_GROUP (G3_DXE) |
| |
| |
| #define FILECODE PROC_MEM_NB_TN_MNDCTTN_FILECODE |
| |
| /*---------------------------------------------------------------------------- |
| * DEFINITIONS AND MACROS |
| * |
| *---------------------------------------------------------------------------- |
| */ |
| #define UNUSED_CLK 4 |
| #define MAX_RD_DQS_DLY 0x1F |
| |
| CONST BIT_FIELD_NAME MemPstateBF[4] = {BFMemPstate0, BFMemPstate1, BFMemPstate2, BFMemPstate3}; |
| /*---------------------------------------------------------------------------- |
| * TYPEDEFS AND STRUCTURES |
| * |
| *---------------------------------------------------------------------------- |
| */ |
| |
| /*---------------------------------------------------------------------------- |
| * PROTOTYPES OF LOCAL FUNCTIONS |
| * |
| *---------------------------------------------------------------------------- |
| */ |
| UINT32 |
| STATIC |
| MemNTotalSyncComponentsTN ( |
| IN OUT MEM_NB_BLOCK *NBPtr |
| ); |
| |
| /*---------------------------------------------------------------------------- |
| * 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 |
| MemNAutoConfigTN ( |
| IN OUT MEM_NB_BLOCK *NBPtr |
| ) |
| { |
| UINT8 i; |
| DIE_STRUCT *MCTPtr; |
| DCT_STRUCT *DCTPtr; |
| MEM_PARAMETER_STRUCT *RefPtr; |
| UINT32 PowerDownMode; |
| |
| RefPtr = NBPtr->RefPtr; |
| MCTPtr = NBPtr->MCTPtr; |
| DCTPtr = NBPtr->DCTPtr; |
| |
| // |
| //====================================================================== |
| // Build Dram Config Lo Register Value |
| //====================================================================== |
| MemNSetBitFieldNb (NBPtr, BFUnBuffDimm, 1); |
| MemNSetBitFieldNb (NBPtr, BFPendRefPaybackS3En, 1); |
| MemNSetBitFieldNb (NBPtr, BFStagRefEn, 1); |
| // |
| //====================================================================== |
| // Build Dram Config Hi Register Value |
| //====================================================================== |
| // |
| // |
| // MemClkFreq |
| // |
| MemNSetBitFieldNb (NBPtr, BFMemClkFreq, MemNGetMemClkFreqIdUnb (NBPtr, DCTPtr->Timings.Speed)); |
| |
| PowerDownMode = 1; |
| IDS_OPTION_HOOK (IDS_POWERDOWN_MODE, &PowerDownMode, &(NBPtr->MemPtr->StdHeader)); |
| MemNSetBitFieldNb (NBPtr, BFPowerDownMode, PowerDownMode); |
| |
| if (NBPtr->MemPstateStage == MEMORY_PSTATE_1ST_STAGE) { |
| MemNBrdcstSetNb (NBPtr, BFM1MemClkFreq, MemNGetMemClkFreqIdUnb (NBPtr, DDR667_FREQUENCY)); |
| MemNBrdcstSetNb (NBPtr, BFRate, MemNGetMemClkFreqIdUnb (NBPtr, DDR667_FREQUENCY) | 0x8); |
| MemNBrdcstSetNb (NBPtr, BFMxMrsEn, 7); |
| } |
| |
| MemNSetBitFieldNb (NBPtr, BFDphyMemPsSelEn, 1); |
| // |
| //====================================================================== |
| // Build Dram MRS Register Value |
| //====================================================================== |
| // |
| MemNSetBitFieldNb (NBPtr, BFPchgPDModeSel, 1); |
| MemNSetBitFieldNb (NBPtr, BFBurstCtrl, 1); |
| |
| //====================================================================== |
| // DRAM Controller Miscellaneous 2 |
| //====================================================================== |
| MemNSetBitFieldNb (NBPtr, BFPerRankTimingEn, 1); |
| IDS_HDT_CONSOLE (MEM_FLOW, "\n\nEnable Per Rank Training....\n\n"); |
| MemNSetBitFieldNb (NBPtr, BFPrtlChPDEnhEn, 0); |
| MemNSetBitFieldNb (NBPtr, BFAggrPDEn, 1); |
| |
| //====================================================================== |
| // GMC to DCT control |
| //====================================================================== |
| MemNSetBitFieldNb (NBPtr, BFGmcTokenLimit, 4); |
| MemNSetBitFieldNb (NBPtr, BFMctTokenLimit, 4); |
| MemNSetBitFieldNb (NBPtr, BFGmcToDctControl1, 0x4444); |
| if ((MCTPtr->LogicalCpuid.Revision & 0x0000000000000100ull ) != 0) { |
| MemNSetBitFieldNb (NBPtr, BFCpuElevPrioDis, 1); |
| } |
| |
| //====================================================================== |
| // Other Registers |
| //====================================================================== |
| // |
| // |
| // Non-SPD Timings |
| // |
| MemNSetBitFieldNb (NBPtr, BFTrwtWB, 0x17); |
| MemNSetBitFieldNb (NBPtr, BFTrwtTO, 0x16); |
| MemNSetBitFieldNb (NBPtr, BFTwrrd, 0xB ); |
| |
| MemNSetBitFieldNb (NBPtr, BFTrdrdSdSc, 0xB); |
| MemNSetBitFieldNb (NBPtr, BFTrdrdSdDc, 0xB); |
| MemNSetBitFieldNb (NBPtr, BFTrdrdDd, 0xB); |
| |
| MemNSetBitFieldNb (NBPtr, BFTwrwrSdSc, 0xB); |
| MemNSetBitFieldNb (NBPtr, BFTwrwrSdDc, 0xB); |
| MemNSetBitFieldNb (NBPtr, BFTwrwrDd, 0xB); |
| |
| MemNSetBitFieldNb (NBPtr, BFWrOdtOnDuration, DEFAULT_WR_ODT_TN); |
| MemNSetBitFieldNb (NBPtr, BFRdOdtOnDuration, DEFAULT_RD_ODT_TN); |
| MemNSetBitFieldNb (NBPtr, BFWrOdtTrnOnDly, DEFAULT_RD_ODT_TRNONDLY_TN); |
| |
| for (i = 0; i < 4; i++) { |
| MemNSetBitFieldNb (NBPtr, BFTstag0 + i, 0x14); |
| } |
| |
| MemNSetBitFieldNb (NBPtr, BFTmrd, 4); |
| MemNSetBitFieldNb (NBPtr, BFFlushWrOnS3StpGnt, 1); |
| MemNSetBitFieldNb (NBPtr, BFFastSelfRefEntryDis, 0); |
| |
| return (BOOLEAN) (MCTPtr->ErrCode < AGESA_FATAL); |
| } |
| |
| /* -----------------------------------------------------------------------------*/ |
| /** |
| * |
| * |
| * This function caps speed based on battery life check. |
| * |
| * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK |
| */ |
| VOID |
| MemNCapSpeedBatteryLifeTN ( |
| IN OUT MEM_NB_BLOCK *NBPtr |
| ) |
| { |
| CONST UINT16 SupportedFreq[] = { |
| DDR2133_FREQUENCY, |
| DDR1866_FREQUENCY, |
| DDR1600_FREQUENCY, |
| DDR1333_FREQUENCY, |
| DDR1066_FREQUENCY, |
| DDR800_FREQUENCY, |
| DDR667_FREQUENCY |
| }; |
| |
| UINT32 FreqNumeratorInMHz; |
| UINT32 FreqDivisor; |
| UINT32 VoltageInuV; |
| UINT32 NBFreq; |
| UINT16 DdrFreq; |
| UINT16 j; |
| INT8 NbPs; |
| CPU_SPECIFIC_SERVICES *FamilySpecificServices; |
| BOOLEAN SkipAdjustNbPs; |
| |
| FamilySpecificServices = NULL; |
| GetCpuServicesOfSocket (NBPtr->MCTPtr->SocketId, (CONST CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, &(NBPtr->MemPtr->StdHeader)); |
| |
| |
| // Find the lowest supported NB Pstate |
| NBFreq = 0; |
| for (NbPs = 3; NbPs >= 0; NbPs--) { |
| if (FamilySpecificServices->GetNbPstateInfo (FamilySpecificServices, |
| NBPtr->MemPtr->PlatFormConfig, |
| &NBPtr->PciAddr, |
| (UINT32) NbPs, |
| &FreqNumeratorInMHz, |
| &FreqDivisor, |
| &VoltageInuV, |
| &(NBPtr->MemPtr->StdHeader))) { |
| if (MemNGetBitFieldNb (NBPtr, MemPstateBF[NbPs]) == 0) { |
| NBFreq = FreqNumeratorInMHz / FreqDivisor; |
| break; |
| } |
| } |
| } |
| |
| ASSERT (NBFreq > 0); |
| |
| // Pick Max MEMCLK that is less than or equal to NCLK |
| DdrFreq = DDR800_FREQUENCY; |
| for (j = 0; j < GET_SIZE_OF (SupportedFreq); j++) { |
| if (NBFreq >= ((UINT32) SupportedFreq[j])) { |
| DdrFreq = SupportedFreq[j]; |
| break; |
| } |
| } |
| |
| // Cap MemClk frequency to lowest NCLK frequency |
| if (NBPtr->DCTPtr->Timings.TargetSpeed > DdrFreq) { |
| NBPtr->DCTPtr->Timings.TargetSpeed = DdrFreq; |
| } |
| |
| // Adjust the NB P-state northbridge voltage |
| SkipAdjustNbPs = FALSE; |
| IDS_OPTION_HOOK (IDS_NBPSDIS_OVERRIDE, &SkipAdjustNbPs, &(NBPtr->MemPtr->StdHeader)); |
| if (SkipAdjustNbPs == FALSE) { |
| MemNAdjustNBPstateVolTN (NBPtr); |
| } |
| |
| // Initialize NbPsCtlReg |
| NBPtr->NbPsCtlReg = 0; |
| } |
| |
| /* -----------------------------------------------------------------------------*/ |
| /** |
| * |
| * |
| * 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] MaxRcvEnDly - Maximum receiver enable delay value |
| */ |
| |
| VOID |
| MemNGetMaxLatParamsTN ( |
| IN OUT MEM_NB_BLOCK *NBPtr, |
| IN UINT16 MaxRcvEnDly, |
| IN OUT UINT16 *MinDlyPtr, |
| IN OUT UINT16 *MaxDlyPtr, |
| IN OUT UINT16 *DlyBiasPtr |
| ) |
| { |
| UINT32 N; |
| UINT32 T; |
| UINT32 P; |
| UINT32 MemClkPeriod; |
| |
| // 1. P = N = T = 0. |
| P = N = T = 0; |
| |
| // Get all sync components BKDG steps 3,4,6 |
| P = MemNTotalSyncComponentsTN (NBPtr); |
| |
| // 7. P = P + CEIL(MAX(D18F2x9C_x0000_00[2A:10]_dct[1:0][DqsRcvEnGrossDelay, DqsRcvEnFineDelay] + |
| // D18F2x9C_x0000_0[3:0]0[7:5]_dct[1:0][RdDqsTime] PCLKs)) + 1 |
| P = P + (MaxRcvEnDly + 31) / 32 + 1; |
| |
| // 10. N = (P/(MemClkFreq * 2) + T) * NclkFreq; Convert from PCLKs plus time to NCLKs. |
| MemClkPeriod = 1000000 / ((NBPtr->MemPstate == MEMORY_PSTATE0) ? NBPtr->DCTPtr->Timings.Speed : DDR667_FREQUENCY); |
| N = ((((P * MemClkPeriod + 1) / 2) + T) * NBPtr->NBClkFreq + 999999) / 1000000; |
| |
| // Calculate a starting MaxRdLatency delay value with steps 5, 9, and 12 excluded |
| *MinDlyPtr = (UINT16) N; |
| |
| *MaxDlyPtr = 0x3FF; |
| |
| // Left edge of MaxRdLat will be added with 1 NCLK and 3 PCLK (1.5 MEMCLK) |
| N = 1; |
| P = 3; |
| N += (((P * MemClkPeriod + 1) / 2) * NBPtr->NBClkFreq + 999999) / 1000000; |
| *DlyBiasPtr = (UINT16) N; |
| } |
| |
| /* -----------------------------------------------------------------------------*/ |
| /** |
| * |
| * |
| * This function sets the maximum round-trip latency in the system from the processor to the DRAM |
| * devices and back. |
| * |
| * |
| * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK |
| * @param[in] MaxRcvEnDly - Maximum receiver enable delay value |
| * |
| */ |
| |
| VOID |
| MemNSetMaxLatencyTN ( |
| 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)); |
| |
| // |
| // Initial value for MaxRdLat used in training |
| // |
| N = 0x55; |
| |
| if (MaxRcvEnDly != 0xFFFF) { |
| // 1. P = N = T = 0. |
| P = N = T = 0; |
| |
| // Get all sync components BKDG steps 3,4,6 |
| P = MemNTotalSyncComponentsTN (NBPtr); |
| |
| // 5. P = P + 5 |
| P += 5; |
| |
| // 7. P = P + CEIL(MAX(D18F2x9C_x0000_00[2A:10]_dct[1:0][DqsRcvEnGrossDelay, DqsRcvEnFineDelay] + |
| // D18F2x9C_x0000_0[3:0]0[6:5]_dct[1:0][RdDqsTime] PCLKs)) + 1 |
| P = P + ((MaxRcvEnDly + MAX_RD_DQS_DLY) + 31) / 32 + 1; |
| |
| // 8. If (NclkFreq/MemClkFreq < 2) then P = P + 4.5 Else P = P + 2.5 |
| if ((NBPtr->NBClkFreq / NBPtr->DCTPtr->Timings.Speed) < 2) { |
| Px2 = P * 2 + 9; |
| } else { |
| Px2 = P * 2 + 5; |
| } |
| |
| // 9. T = T + 1050 ps |
| T += 1050; |
| |
| // 10. N = (P/(MemClkFreq * 2) + T) * NclkFreq; Convert from PCLKs plus time to NCLKs. |
| MemClkPeriod = 1000000 / NBPtr->DCTPtr->Timings.Speed; |
| N = ((((Px2 * MemClkPeriod + 3) / 4) + T) * NBPtr->NBClkFreq + 999999) / 1000000; |
| |
| // 11. D18F2x210_dct[1:0]_nbp[3:0][MaxRdLatency] = CEIL(N) - 1 |
| N = N - 1; |
| } |
| |
| NBPtr->DCTPtr->Timings.MaxRdLat = (UINT16) N; |
| IDS_HDT_CONSOLE (MEM_FLOW, "\t\tMaxRdLat: %03x\n", N); |
| MemNSetBitFieldNb (NBPtr, BFMaxLatency, N); |
| } |
| |
| /*----------------------------------------------------------------------------- |
| * |
| * |
| * This function set MaxRdLat after HW receiver enable training is completed |
| * |
| * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK |
| * @param[in,out] OptParam - Optional parameter |
| * |
| * @return TRUE |
| * ---------------------------------------------------------------------------- |
| */ |
| BOOLEAN |
| MemNExitPhyAssistedTrainingTN ( |
| IN OUT MEM_NB_BLOCK *NBPtr, |
| IN OUT VOID *OptParam |
| ) |
| { |
| UINT8 Dct; |
| UINT8 ChipSel; |
| MEM_TECH_BLOCK *TechPtr; |
| |
| TechPtr = NBPtr->TechPtr; |
| |
| // Calculate Max Latency for both channels to prepare for position training |
| for (Dct = 0; Dct < MAX_DCTS_PER_NODE_TN ; Dct++) { |
| IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct); |
| NBPtr->SwitchDCT (NBPtr, Dct); |
| |
| // Reset DisAutoRefresh and ZqcsInterval for position training. |
| if (NBPtr->DCTPtr->Timings.DctMemSize != 0) { |
| MemNSetBitFieldNb (NBPtr, BFDisAutoRefresh, 1); |
| MemNSetBitFieldNb (NBPtr, BFZqcsInterval, 0); |
| MemNSetBitFieldNb (NBPtr, BFRx4thStgEn, 0); |
| MemNSetBitFieldNb (NBPtr, BFRxBypass3rd4thStg, 4); |
| } |
| |
| if (TechPtr->FindMaxDlyForMaxRdLat (TechPtr, &ChipSel)) { |
| NBPtr->SetMaxLatency (NBPtr, TechPtr->MaxDlyForMaxRdLat); |
| } |
| } |
| |
| return (BOOLEAN) (NBPtr->MCTPtr->ErrCode < AGESA_FATAL); |
| } |
| |
| /*---------------------------------------------------------------------------- |
| * LOCAL FUNCTIONS |
| * |
| *---------------------------------------------------------------------------- |
| */ |
| |
| /* -----------------------------------------------------------------------------*/ |
| /** |
| * |
| * |
| * This function gets the total of sync components for Max Read Latency calculation |
| * |
| * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK |
| * |
| * @return Total in PCLKs |
| */ |
| UINT32 |
| STATIC |
| MemNTotalSyncComponentsTN ( |
| IN OUT MEM_NB_BLOCK *NBPtr |
| ) |
| { |
| UINT32 P; |
| |
| P = 0; |
| |
| // 3. If (D18F2x9C_x0000_0004_dct[1:0][AddrCmdSetup] = 0 & D18F2x9C_x0000_0004_dct[1:0][CsOdt- |
| // Setup] = 0 & D18F2x9C_x0000_0004_dct[1:0][CkeSetup] = 0) |
| // then P = P + 1 |
| // else P = P + 2 |
| if ((MemNGetBitFieldNb (NBPtr, BFAddrTmgControl) & 0x0202020) == 0) { |
| P += 1; |
| } else { |
| P += 2; |
| } |
| |
| // 4. P = P + (8 - D18F2x210_dct[1:0]_nbp[3:0][RdPtrInit]) |
| P = P + (8 - (UINT16) MemNGetBitFieldNb (NBPtr, BFRdPtrInit)); |
| |
| // 6. P = P + (2 * (D18F2x200_dct[1:0][Tcl] - 1 clocks)) |
| P = P + (2 * (MemNGetBitFieldNb (NBPtr, BFTcl) - 1)); |
| |
| return P; |
| } |
| |
| /* -----------------------------------------------------------------------------*/ |
| /** |
| * |
| * This function calculates and programs NB P-state dependent registers |
| * |
| * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK |
| * |
| */ |
| |
| VOID |
| MemNProgramNbPstateDependentRegistersTN ( |
| IN OUT MEM_NB_BLOCK *NBPtr |
| ) |
| { |
| UINT8 RdPtrInit; |
| UINT8 Dct; |
| MEMORY_BUS_SPEED MemClkSpeed; |
| |
| for (Dct = 0; Dct < MAX_DCTS_PER_NODE_TN; Dct++) { |
| MemNSwitchDCTNb (NBPtr, Dct); |
| if (NBPtr->DCTPtr->Timings.DctMemSize != 0) { |
| break; |
| } |
| } |
| |
| if (MemNGetBitFieldNb (NBPtr, MemPstateBF[MemNGetBitFieldNb (NBPtr, BFNbPsSel)]) == 0) { |
| MemClkSpeed = NBPtr->DCTPtr->Timings.Speed; |
| } else { |
| MemClkSpeed = MemNGetMemClkFreqUnb (NBPtr, (UINT8) MemNGetBitFieldNb (NBPtr, BFM1MemClkFreq)); |
| } |
| IDS_HDT_CONSOLE (MEM_FLOW, "\t\tMemclk Freq: %d\n", MemClkSpeed); |
| |
| // NCLK:MCLK ratio DDR rate (MT/s) RdPtrInit |
| // < 2:1 < 2133 0011b (2.5T) |
| // < 2:1 2133 <= rate <= 2400 0011b (2.5T) or 0010b (3T) |
| // For each NB P-state, IF any D18F2x9C_x0000_0[3:0]0[2:1]_dct[1:0]_mp[MemPstate][WrDat- |
| // GrossDly] ==0 THEN RdPtrInit=0010b ELSE RdPtrInit=0011b |
| // >=2:1 < 1866 0110b |
| // >=2:1 1866 <= rate < 2400 0101b |
| // >=2:1 2400 0100b |
| if (NBPtr->NBClkFreq < (UINT32) (MemClkSpeed * 2)) { |
| RdPtrInit = ((MemClkSpeed >= DDR2133_FREQUENCY) && (NBPtr->TechPtr->GetMinMaxGrossDly (NBPtr->TechPtr, AccessWrDatDly, FALSE) == 0)) ? 2 : 3; |
| } else { |
| RdPtrInit = (MemClkSpeed < DDR1866_FREQUENCY) ? 6 : ((MemClkSpeed < DDR2400_FREQUENCY) ? 5 : 4); |
| } |
| MemNBrdcstSetNb (NBPtr, BFRdPtrInit, RdPtrInit); |
| IDS_HDT_CONSOLE (MEM_FLOW, "\t\tRdPtr: %d\n", RdPtrInit); |
| |
| for (Dct = 0; Dct < MAX_DCTS_PER_NODE_TN; Dct++) { |
| MemNSwitchDCTNb (NBPtr, Dct); |
| if (NBPtr->DCTPtr->Timings.DctMemSize != 0) { |
| // Set ProcOdtAdv |
| if ((NBPtr->ChannelPtr->SODimmPresent != 0) && (NBPtr->DCTPtr->Timings.Speed <= DDR1333_FREQUENCY)) { |
| MemNSetBitFieldNb (NBPtr, BFProcOdtAdv, 0); |
| } else { |
| MemNSetBitFieldNb (NBPtr, BFProcOdtAdv, 0x4000); |
| } |
| } |
| } |
| |
| MemNBrdcstSetNb (NBPtr, BFDataTxFifoWrDly, 0); |
| |
| IDS_OPTION_HOOK (IDS_NBPS_REG_OVERRIDE, NBPtr, &NBPtr->MemPtr->StdHeader); |
| MemFInitTableDrive (NBPtr, MTAfterNbPstateChange); |
| } |
| |
| /* -----------------------------------------------------------------------------*/ |
| /** |
| * |
| * |
| * This is a general purpose function that executes before DRAM init |
| * |
| * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK |
| * |
| */ |
| |
| VOID |
| MemNBeforeDramInitTN ( |
| IN OUT MEM_NB_BLOCK *NBPtr |
| ) |
| { |
| UINT8 Dct; |
| |
| for (Dct = 0; Dct < MAX_DCTS_PER_NODE_TN; Dct++) { |
| MemNSwitchDCTNb (NBPtr, Dct); |
| if (NBPtr->DCTPtr->Timings.DctMemSize != 0) { |
| // |
| // 2.10.6.7 DCT Training Specific Configuration |
| // |
| MemNSetBitFieldNb (NBPtr, BFAddrCmdTriEn, 0); |
| MemNSetBitFieldNb (NBPtr, BFDisAutoRefresh, 1); |
| MemNSetBitFieldNb (NBPtr, BFForceAutoPchg, 0); |
| MemNSetBitFieldNb (NBPtr, BFDynPageCloseEn, 0); |
| MemNSetBitFieldNb (NBPtr, BFBankSwizzleMode, 0); |
| MemNSetBitFieldNb (NBPtr, BFDcqBypassMax, 0); |
| MemNSetBitFieldNb (NBPtr, BFPowerDownEn, 0); |
| MemNSetBitFieldNb (NBPtr, BFZqcsInterval, 0); |
| MemNSetBitFieldNb (NBPtr, BFRxMaxDurDllNoLock, 0); |
| MemNSetBitFieldNb (NBPtr, BFTxMaxDurDllNoLock, 0); |
| MemNSetBitFieldNb (NBPtr, BFEnRxPadStandby, 0); |
| MemNSetBitFieldNb (NBPtr, BFBankSwap, 0); |
| MemNSetBitFieldNb (NBPtr, BFODTSEn, 0); |
| MemNSetBitFieldNb (NBPtr, BFDctSelIntLvEn, 0); |
| MemNSetBitFieldNb (NBPtr, BFCmdThrottleMode, 0); |
| MemNSetBitFieldNb (NBPtr, BFBwCapEn, 0); |
| } |
| } |
| } |
| |
| /* -----------------------------------------------------------------------------*/ |
| /** |
| * |
| * This function modifies CS interleaving low address according to several conditions for TN. |
| * |
| * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK |
| * @param[in,out] *LowBit - Pointer to low bit |
| * |
| */ |
| |
| BOOLEAN |
| MemNCSIntLvLowAddrAdjTN ( |
| IN OUT MEM_NB_BLOCK *NBPtr, |
| IN OUT VOID *LowBit |
| ) |
| { |
| UINT8 DctSelIntLvAddr; |
| |
| DctSelIntLvAddr = (UINT8) MemNGetBitFieldNb (NBPtr, BFDctSelIntLvAddr); |
| // |
| //D18F2x[5C:40]_dct[1:0][15:5] = BaseAddr[21:11] && |
| //D18F2x[6C:60]_dct[1:0][15:5] = AddrMask[21:11], so *LowBit needs to be added with 2. |
| // |
| *(UINT8 *) LowBit += 2; |
| |
| if (MemNGetBitFieldNb (NBPtr, BFBankSwap) == 1) { |
| if (DctSelIntLvAddr == 4) { |
| *(UINT8 *) LowBit = 5; |
| } else { |
| *(UINT8 *) LowBit = 6; |
| } |
| } |
| return TRUE; |
| } |
| |
| /* -----------------------------------------------------------------------------*/ |
| /** |
| * |
| * |
| * This function releases the NB P-state force. |
| * |
| * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK |
| * @param[in,out] OptParam - Optional parameter |
| * |
| * @return TRUE |
| */ |
| BOOLEAN |
| MemNReleaseNbPstateTN ( |
| IN OUT MEM_NB_BLOCK *NBPtr, |
| IN OUT VOID *OptParam |
| ) |
| { |
| CPU_SPECIFIC_SERVICES *FamilySpecificServices; |
| GetCpuServicesOfCurrentCore ((CONST CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, &NBPtr->MemPtr->StdHeader); |
| |
| // 6. Restore the initial D18F5x170[SwNbPstateLoDis, NbPstateDisOnP0] values. |
| MemNSetBitFieldNb (NBPtr, BFNbPstateCtlReg, (MemNGetBitFieldNb (NBPtr, BFNbPstateCtlReg) & 0xFFFF9FFF) | (NBPtr->NbPsCtlReg & 0x6000)); |
| // 7. Restore the initial D18F5x170[NbPstateThreshold, NbPstateHi] values. |
| MemNSetBitFieldNb (NBPtr, BFNbPstateCtlReg, (MemNGetBitFieldNb (NBPtr, BFNbPstateCtlReg) & 0xFFFFF13F) | (NBPtr->NbPsCtlReg & 0x0EC0)); |
| // 8. Restore the initial D18F5x170[NbPstateLo] values. |
| MemNSetBitFieldNb (NBPtr, BFNbPstateLo, (NBPtr->NbPsCtlReg >> 3) & 3); |
| |
| // Clear NbPsSel to 0 |
| MemNSetBitFieldNb (NBPtr, BFNbPsSel, 0); |
| // Update TSC rate |
| FamilySpecificServices->GetTscRate (FamilySpecificServices, &NBPtr->MemPtr->TscRate, &NBPtr->MemPtr->StdHeader); |
| |
| if (MemNGetBitFieldNb (NBPtr, BFMemPsSel) != 0) { |
| MemNChangeMemPStateContextNb (NBPtr, 0); |
| } |
| |
| return TRUE; |
| } |
| |
| /* -----------------------------------------------------------------------------*/ |
| /** |
| * |
| * |
| * This function handles multiple stage of training when multiple Mem Pstate is enabled |
| * |
| * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK |
| * @param[in,out] OptParam - Optional parameter |
| * |
| * @return TRUE |
| * |
| */ |
| |
| BOOLEAN |
| MemNMemPstateStageChangeTN ( |
| IN OUT MEM_NB_BLOCK *NBPtr, |
| IN OUT VOID *OptParam |
| ) |
| { |
| BOOLEAN RetVal; |
| TRN_DLY_TYPE AccessType; |
| UINT8 Dct; |
| UINT8 ChipSel; |
| UINT8 ByteLane; |
| UINT16 CsEnabled; |
| UINT16 TrnDly; |
| |
| RetVal = FALSE; |
| |
| if (NBPtr->MemPstateStage == MEMORY_PSTATE_1ST_STAGE) { |
| MemNChangeMemPStateContextNb (NBPtr, 1); |
| // Load memory registers in M1 context from data saved in the heap |
| IDS_HDT_CONSOLE (MEM_FLOW, "\nLoad Training registers for M1 with DDR667 training result\n"); |
| for (Dct = 0; Dct < MAX_DCTS_PER_NODE_TN; Dct++) { |
| MemNSwitchDCTNb (NBPtr, Dct); |
| if (NBPtr->DCTPtr->Timings.DctMemSize != 0) { |
| // Save MemPstate 1 data in output data structures |
| LibAmdMemCopy (NBPtr->ChannelPtr->RcvEnDlysMemPs1, NBPtr->ChannelPtr->RcvEnDlys, (MAX_DIMMS * MAX_DELAYS) * 2, &(NBPtr->MemPtr->StdHeader)); |
| LibAmdMemCopy (NBPtr->ChannelPtr->RdDqsDlysMemPs1, NBPtr->ChannelPtr->RdDqsDlys, MAX_DIMMS * MAX_DELAYS, &(NBPtr->MemPtr->StdHeader)); |
| LibAmdMemCopy (NBPtr->ChannelPtr->WrDqsDlysMemPs1, NBPtr->ChannelPtr->WrDqsDlys, MAX_DIMMS * MAX_DELAYS, &(NBPtr->MemPtr->StdHeader)); |
| LibAmdMemCopy (NBPtr->ChannelPtr->WrDatDlysMemPs1, NBPtr->ChannelPtr->WrDatDlys, MAX_DIMMS * MAX_DELAYS, &(NBPtr->MemPtr->StdHeader)); |
| LibAmdMemCopy (NBPtr->ChannelPtr->RdDqs2dDlysMemPs1, NBPtr->ChannelPtr->RdDqs2dDlys, MAX_DIMMS * MAX_NUMBER_LANES, &(NBPtr->MemPtr->StdHeader)); |
| LibAmdMemCopy (NBPtr->ChannelPtr->RdDqsMinDlysMemPs1, NBPtr->ChannelPtr->RdDqsMinDlys, MAX_DIMMS * MAX_DELAYS, &(NBPtr->MemPtr->StdHeader)); |
| LibAmdMemCopy (NBPtr->ChannelPtr->RdDqsMaxDlysMemPs1, NBPtr->ChannelPtr->RdDqsMaxDlys, MAX_DIMMS * MAX_DELAYS, &(NBPtr->MemPtr->StdHeader)); |
| LibAmdMemCopy (NBPtr->ChannelPtr->WrDatMinDlysMemPs1, NBPtr->ChannelPtr->WrDatMinDlys, MAX_DIMMS * MAX_DELAYS, &(NBPtr->MemPtr->StdHeader)); |
| LibAmdMemCopy (NBPtr->ChannelPtr->WrDatMaxDlysMemPs1, NBPtr->ChannelPtr->WrDatMaxDlys, MAX_DIMMS * MAX_DELAYS, &(NBPtr->MemPtr->StdHeader)); |
| LibAmdMemCopy (NBPtr->ChannelPtr->FailingBitMaskMemPs1, NBPtr->ChannelPtr->FailingBitMask, MAX_CS_PER_CHANNEL * MAX_DELAYS, &(NBPtr->MemPtr->StdHeader)); |
| |
| CsEnabled = NBPtr->DCTPtr->Timings.CsEnabled; |
| // Set Memory Pstate 1 training value into registers |
| for (AccessType = AccessRcvEnDly; AccessType <= AccessWrDqsDly; AccessType ++) { |
| for (ChipSel = 0; ChipSel < MAX_CS_PER_CHANNEL_TN; ChipSel = ChipSel + NBPtr->CsPerDelay) { |
| if ((CsEnabled & ((UINT16) ((NBPtr->CsPerDelay == 2)? 3 : 1) << ChipSel)) != 0) { |
| for (ByteLane = 0; ByteLane < 8; ByteLane++) { |
| TrnDly = (UINT16) GetTrainDlyFromHeapNb (NBPtr, AccessType, DIMM_BYTE_ACCESS (ChipSel / NBPtr->CsPerDelay, ByteLane)); |
| NBPtr->SetTrainDly (NBPtr, AccessType, DIMM_BYTE_ACCESS (ChipSel / NBPtr->CsPerDelay, ByteLane), TrnDly); |
| } |
| } |
| } |
| } |
| |
| if (NBPtr->RefPtr->EnablePowerDown) { |
| MemNSetTxpNb (NBPtr); |
| MemNSetBitFieldNb (NBPtr, BFPchgPDEnDelay, (MAX (MAX ((NBPtr->DCTPtr->Timings.CasL + 5), |
| (UINT8) (MemNGetBitFieldNb (NBPtr, BFTcwl) + NBPtr->DCTPtr->Timings.Twr + 5)), |
| (UINT8) MemNGetBitFieldNb (NBPtr, BFTmod)))); |
| MemNSetBitFieldNb (NBPtr, BFAggrPDDelay, 0x20); |
| } |
| MemNSetOtherTimingTN (NBPtr); |
| // Save timing data structure for memory Pstate 1 |
| LibAmdMemCopy (NBPtr->DCTPtr->TimingsMemPs1, &(NBPtr->DCTPtr->Timings), sizeof (CH_TIMING_STRUCT), &(NBPtr->MemPtr->StdHeader)); |
| |
| MemFInitTableDrive (NBPtr, MTAfterMemPstate1PartialTrn); |
| } |
| } |
| |
| // Switch back to M0 context |
| MemNChangeMemPStateContextNb (NBPtr, 0); |
| |
| // Load memory registers in M1 context from data saved in the heap |
| IDS_HDT_CONSOLE (MEM_FLOW, "\nGoing into training stage 2. Complete training at DDR667 is done.\n"); |
| NBPtr->MemPstateStage = MEMORY_PSTATE_2ND_STAGE; |
| } else if ((NBPtr->MemPstateStage == MEMORY_PSTATE_2ND_STAGE) && (NBPtr->DCTPtr->Timings.TargetSpeed == NBPtr->DCTPtr->Timings.Speed)) { |
| IDS_HDT_CONSOLE (MEM_FLOW, "\nGoing into training stage 3. Partial training at all frequencies is done.\n"); |
| NBPtr->MemPstateStage = MEMORY_PSTATE_3RD_STAGE; |
| RetVal = TRUE; |
| } else { |
| // MemPstate is disabled. Do not go through the MemPstate handling flow. |
| RetVal = TRUE; |
| } |
| |
| return RetVal; |
| } |
| |
| /* -----------------------------------------------------------------------------*/ |
| /** |
| * |
| * |
| * This function Sets Power Down options and enables Power Down |
| * |
| * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK |
| * |
| * The following registers are set: |
| * BFPowerDownMode BFPrtlChPDEnhEn |
| * BFTxp BFAggrPDDelay |
| * BFTxpDll BFAggrPDEn |
| * BFPchgPDEnDelay BFPowerDownEn |
| * |
| * NOTE: Delay values must be set before turning on the associated Enable bit |
| */ |
| VOID |
| MemNPowerDownCtlTN ( |
| IN OUT MEM_NB_BLOCK *NBPtr |
| ) |
| { |
| UINT8 PowerDownMode; |
| UINT8 Tmod; |
| UINT8 Twr; |
| UINT8 Tcwl; |
| UINT8 Tcl; |
| |
| if (NBPtr->RefPtr->EnablePowerDown) { |
| // |
| // PowerDownMode |
| // |
| PowerDownMode = (UINT8) 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); |
| } |
| // |
| // Txp |
| // |
| MemNSetTxpNb (NBPtr); |
| // |
| // PchgPDModeSel is set elswhere. |
| // |
| // PchgPDEnDelay = MAX(Tcl + 5, Tcwl + Twr + 5, Tmod) |
| // |
| Tmod = (UINT8) MemNGetBitFieldNb (NBPtr, BFTmod); |
| Twr = NBPtr->DCTPtr->Timings.Twr; |
| Tcwl = (UINT8) MemNGetBitFieldNb (NBPtr, BFTcwl); |
| Tcl = NBPtr->DCTPtr->Timings.CasL; |
| MemNSetBitFieldNb (NBPtr, BFPchgPDEnDelay, (MAX (MAX ((Tcl + 5), (Tcwl + Twr + 5)), Tmod))); |
| // |
| // Partial Channel Power Down |
| // |
| MemNSetBitFieldNb (NBPtr, BFPrtlChPDDynDly, 0); |
| MemNSetBitFieldNb (NBPtr, BFPrtlChPDEnhEn, 0); |
| // |
| // Aggressive PowerDown |
| // |
| MemNSetBitFieldNb (NBPtr, BFAggrPDDelay, 0x20); |
| MemNSetBitFieldNb (NBPtr, BFAggrPDEn, 1); |
| } |
| } |
| |
| /* -----------------------------------------------------------------------------*/ |
| /** |
| * |
| * |
| * Always set upper 2 bits of CKETri bitfield |
| * |
| * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK |
| * |
| */ |
| VOID |
| MemNBeforePlatformSpecTN ( |
| IN OUT MEM_NB_BLOCK *NBPtr |
| ) |
| { |
| MemNSetBitFieldNb (NBPtr, BFCKETri, 0xC | MemNGetBitFieldNb (NBPtr, BFCKETri)); |
| } |