7 * Main Memory Flow Entrypoint file
9 * @xrefitem bom "File Content Label" "Release Content"
11 * @e sub-project: (Mem/Main)
12 * @e \$Revision: 56279 $ @e \$Date: 2011-07-11 13:11:28 -0600 (Mon, 11 Jul 2011) $
15 /*****************************************************************************
17 * Copyright (C) 2012 Advanced Micro Devices, Inc.
18 * All rights reserved.
20 * Redistribution and use in source and binary forms, with or without
21 * modification, are permitted provided that the following conditions are met:
22 * * Redistributions of source code must retain the above copyright
23 * notice, this list of conditions and the following disclaimer.
24 * * Redistributions in binary form must reproduce the above copyright
25 * notice, this list of conditions and the following disclaimer in the
26 * documentation and/or other materials provided with the distribution.
27 * * Neither the name of Advanced Micro Devices, Inc. nor the names of
28 * its contributors may be used to endorse or promote products derived
29 * from this software without specific prior written permission.
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
32 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
33 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
34 * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
35 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
36 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
38 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
40 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 * ***************************************************************************
47 *----------------------------------------------------------------------------
50 *----------------------------------------------------------------------------
56 #include "AdvancedApi.h"
58 #include "cpuRegisters.h"
59 #include "cpuServices.h"
60 #include "GeneralServices.h"
61 #include "cpuFamilyTranslation.h"
62 #include "OptionMemory.h"
67 #include "heapManager.h"
72 #define FILECODE PROC_MEM_MAIN_MMFLOW_FILECODE
75 extern MEM_NB_SUPPORT memNBInstalled[];
76 extern MEM_TECH_CONSTRUCTOR* memTechInstalled[];
77 extern MEM_FEAT_BLOCK_MAIN MemFeatMain;
78 extern MEM_FLOW_CFG* memFlowControlInstalled[];
80 /*----------------------------------------------------------------------------
81 * DEFINITIONS AND MACROS
83 *----------------------------------------------------------------------------
86 /*----------------------------------------------------------------------------
87 * TYPEDEFS AND STRUCTURES
89 *----------------------------------------------------------------------------
92 /*----------------------------------------------------------------------------
93 * PROTOTYPES OF LOCAL FUNCTIONS
95 *----------------------------------------------------------------------------
100 IN OUT MEM_DATA_STRUCT *MemPtr
103 /*----------------------------------------------------------------------------
106 *----------------------------------------------------------------------------
108 /* -----------------------------------------------------------------------------*/
112 * This function is the main memory configuration function for DR DDR3
116 * Run-Time Requirements:
117 * 1. Complete Hypertransport Bus Configuration
118 * 2. AmdMemInitDataStructDef must be run to set default values
119 * 3. MSR bit to allow access to high PCI regs set on all nodes
120 * 4. BSP in Big Real Mode
122 * 6. MCG_CTL=-1, MC4_EN=0 for all CPUs
123 * 7. MCi_STS from shutdown/warm reset recorded (if desired) prior to entry
124 * 8. All var MTRRs reset to zero
125 * 9. State of NB_CFG.DisDatMsk set properly on all CPUs
127 * @param[in,out] *MemPtr - Pointer to the MEM_DATA_STRUCT
129 * @return AGESA_STATUS
137 IN OUT MEM_DATA_STRUCT *MemPtr
140 MEM_SHARED_DATA mmSharedData;
141 MEM_MAIN_DATA_BLOCK mmData;
143 MEM_TECH_BLOCK *TechPtr;
144 ALLOCATE_HEAP_PARAMS AllocHeapParams;
150 CPU_SPECIFIC_SERVICES *FamilySpecificServices;
152 ASSERT (MemPtr != NULL);
154 AGESA_TESTPOINT (TpProcMemAmdMemAuto, &MemPtr->StdHeader);
156 IDS_HDT_CONSOLE (MEM_FLOW, "MEM PARAMS:\n");
157 IDS_HDT_CONSOLE (MEM_FLOW, "\tBottomIo : %04x\n", MemPtr->ParameterListPtr->BottomIo);
158 IDS_HDT_CONSOLE (MEM_FLOW, "\tMemHoleRemap : %d\n", MemPtr->ParameterListPtr->MemHoleRemapping);
159 IDS_HDT_CONSOLE (MEM_FLOW, "\tLimitBelow1TB : %d\n", MemPtr->ParameterListPtr->LimitMemoryToBelow1Tb);
160 IDS_HDT_CONSOLE (MEM_FLOW, "\tUserTimingMode : %d\n", MemPtr->ParameterListPtr->UserTimingMode);
161 IDS_HDT_CONSOLE (MEM_FLOW, "\tMemClockValue : %d\n", MemPtr->ParameterListPtr->MemClockValue);
162 IDS_HDT_CONSOLE (MEM_FLOW, "\tBankIntlv : %d\n", MemPtr->ParameterListPtr->EnableBankIntlv);
163 IDS_HDT_CONSOLE (MEM_FLOW, "\tNodeIntlv : %d\n", MemPtr->ParameterListPtr->EnableNodeIntlv);
164 IDS_HDT_CONSOLE (MEM_FLOW, "\tChannelIntlv : %d\n", MemPtr->ParameterListPtr->EnableChannelIntlv);
165 IDS_HDT_CONSOLE (MEM_FLOW, "\tEccFeature : %d\n", MemPtr->ParameterListPtr->EnableEccFeature);
166 IDS_HDT_CONSOLE (MEM_FLOW, "\tPowerDown : %d\n", MemPtr->ParameterListPtr->EnablePowerDown);
167 IDS_HDT_CONSOLE (MEM_FLOW, "\tOnLineSpare : %d\n", MemPtr->ParameterListPtr->EnableOnLineSpareCtl);
168 IDS_HDT_CONSOLE (MEM_FLOW, "\tParity : %d\n", MemPtr->ParameterListPtr->EnableParity);
169 IDS_HDT_CONSOLE (MEM_FLOW, "\tBankSwizzle : %d\n", MemPtr->ParameterListPtr->EnableBankSwizzle);
170 IDS_HDT_CONSOLE (MEM_FLOW, "\tMemClr : %d\n", MemPtr->ParameterListPtr->EnableMemClr);
171 IDS_HDT_CONSOLE (MEM_FLOW, "\tUmaMode : %d\n", MemPtr->ParameterListPtr->UmaMode);
172 IDS_HDT_CONSOLE (MEM_FLOW, "\tUmaSize : %d\n", MemPtr->ParameterListPtr->UmaSize);
173 IDS_HDT_CONSOLE (MEM_FLOW, "\tMemRestoreCtl : %d\n", MemPtr->ParameterListPtr->MemRestoreCtl);
174 IDS_HDT_CONSOLE (MEM_FLOW, "\tSaveMemContextCtl : %d\n", MemPtr->ParameterListPtr->SaveMemContextCtl);
175 IDS_HDT_CONSOLE (MEM_FLOW, "\tExternalVrefCtl : %d\n", MemPtr->ParameterListPtr->ExternalVrefCtl );
176 IDS_HDT_CONSOLE (MEM_FLOW, "\tForceTrainMode : %d\n\n", MemPtr->ParameterListPtr->ForceTrainMode );
178 //----------------------------------------------------------------------------
179 // Get TSC rate, which will be used later in Wait10ns routine
180 //----------------------------------------------------------------------------
181 GetCpuServicesOfCurrentCore ((CONST CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, &MemPtr->StdHeader);
182 FamilySpecificServices->GetTscRate (FamilySpecificServices, &MemPtr->TscRate, &MemPtr->StdHeader);
184 //----------------------------------------------------------------------------
186 //----------------------------------------------------------------------------
187 AGESA_TESTPOINT (TpProcMemBeforeSpdProcessing, &MemPtr->StdHeader);
188 MemSPDDataProcess (MemPtr);
190 //----------------------------------------------------------------
191 // Initialize Main Data Block
192 //----------------------------------------------------------------
193 mmData.MemPtr = MemPtr;
194 mmData.mmSharedPtr = &mmSharedData;
195 LibAmdMemFill (&mmSharedData, 0, sizeof (mmSharedData), &MemPtr->StdHeader);
196 mmSharedData.DimmExcludeFlag = NORMAL;
197 mmSharedData.NodeIntlv.IsValid = FALSE;
198 //----------------------------------------------------------------
199 // Discover populated CPUs
201 //----------------------------------------------------------------
202 Retval = MemSocketScan (&mmData);
203 if (Retval == AGESA_FATAL) {
206 DieCount = mmData.DieCount;
207 //----------------------------------------------------------------
209 // Allocate Memory for NB and Tech Blocks
214 // +---+---+---+---+---+---+---+---+
215 // | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | NB Blocks
216 // +---+---+---+---+---+---+---+---+
220 // +---+---+---+---+---+---+---+---+
221 // | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | Tech Blocks
222 // +---+---+---+---+---+---+---+---+
225 //----------------------------------------------------------------
226 AllocHeapParams.RequestedBufferSize = (DieCount * (sizeof (MEM_NB_BLOCK) + sizeof (MEM_TECH_BLOCK)));
227 AllocHeapParams.BufferHandle = AMD_MEM_AUTO_HANDLE;
228 AllocHeapParams.Persist = HEAP_LOCAL_CACHE;
229 if (AGESA_SUCCESS != HeapAllocateBuffer (&AllocHeapParams, &MemPtr->StdHeader)) {
230 ASSERT(FALSE); // NB and Tech Block Heap allocate error
233 NBPtr = (MEM_NB_BLOCK *)AllocHeapParams.BufferPtr;
234 TechPtr = (MEM_TECH_BLOCK *) (&NBPtr[DieCount]);
235 mmData.NBPtr = NBPtr;
236 mmData.TechPtr = TechPtr;
238 //----------------------------------------------------------------
241 //----------------------------------------------------------------
242 for (Die = 0 ; Die < DieCount ; Die++ ) {
244 while (memNBInstalled[i].MemConstructNBBlock != 0) {
245 if (memNBInstalled[i].MemConstructNBBlock (&NBPtr[Die], MemPtr, memNBInstalled[i].MemFeatBlock, &mmSharedData, Die) == TRUE) {
250 // Couldn't find a NB which supported this family
251 if (memNBInstalled[i].MemConstructNBBlock == 0) {
255 //----------------------------------------------------------------
256 // Create Technology Blocks
258 //----------------------------------------------------------------
259 for (Die = 0 ; Die < DieCount ; Die++ ) {
261 while (memTechInstalled[i] != NULL) {
262 if (memTechInstalled[i] (&TechPtr[Die], &NBPtr[Die])) {
263 NBPtr[Die].TechPtr = &TechPtr[Die];
268 // Couldn't find a Tech block which supported this family
269 if (memTechInstalled[i] == NULL) {
273 //----------------------------------------------------------------
275 // MEMORY INITIALIZATION TASKS
277 //----------------------------------------------------------------
279 while (memFlowControlInstalled[i] != NULL) {
280 Retval = memFlowControlInstalled[i] (&mmData);
281 if (MemPtr->IsFlowControlSupported == TRUE) {
287 //----------------------------------------------------------------
288 // Deallocate NB register tables
289 //----------------------------------------------------------------
290 for (Tab = 0; Tab < NumberOfNbRegTables; Tab++) {
291 HeapDeallocateBuffer (GENERATE_MEM_HANDLE (ALLOC_NB_REG_TABLE, Tab, 0, 0), &MemPtr->StdHeader);
294 //----------------------------------------------------------------
295 // Check for errors and return
296 //----------------------------------------------------------------
297 AGESA_TESTPOINT (TpProcMemEnd, &MemPtr->StdHeader);
298 for (Die = 0; Die < DieCount; Die++) {
299 if (NBPtr[Die].MCTPtr->ErrCode > Retval) {
300 Retval = NBPtr[Die].MCTPtr->ErrCode;
307 /* -----------------------------------------------------------------------------*/
311 * This function fills a default SPD buffer with SPD values for all DIMMs installed in the system
313 * The SPD Buffer is populated with a Socket-Channel-Dimm centric view of the Dimms. At this
314 * point, the Memory controller type is not known, and the platform BIOS does not know the anything
315 * about which DIMM is on which DCT. So the DCT relationship is abstracted from the arrangement
316 * of SPD information here. We use the utility functions GetSpdSocketIndex(), GetMaxChannelsPerSocket(),
317 * and GetMaxDimmsPerChannel() to Map the SPD data according to which Socket-relative channel the DIMMs
318 * are connected to. The functions rely on either the maximum values in the
319 * PlatformSpecificOverridingTable or if unspecified, the absolute maximums in AGESA.H.
321 * This mapping is translated in the Northbridge object Constructor and the Technology block constructor.
323 * @param[in,out] *MemPtr - Pointer to the MEM_DATA_STRUCT
330 IN OUT MEM_DATA_STRUCT *MemPtr
339 UINT8 MaxChannelsPerSocket;
340 UINT8 MaxDimmsPerChannel;
341 SPD_DEF_STRUCT *DimmSPDPtr;
343 ALLOCATE_HEAP_PARAMS AllocHeapParams;
344 AGESA_READ_SPD_PARAMS SpdParam;
346 ASSERT (MemPtr != NULL);
347 MaxSockets = (UINT8) (0x000000FF & GetPlatformNumberOfSockets ());
348 PsoTable = MemPtr->ParameterListPtr->PlatformMemoryConfiguration;
350 // Allocate heap for the table
352 AllocHeapParams.RequestedBufferSize = (GetSpdSocketIndex (PsoTable, MaxSockets, &MemPtr->StdHeader) * sizeof (SPD_DEF_STRUCT));
353 AllocHeapParams.BufferHandle = AMD_MEM_SPD_HANDLE;
354 AllocHeapParams.Persist = HEAP_LOCAL_CACHE;
355 if (HeapAllocateBuffer (&AllocHeapParams, &MemPtr->StdHeader) == AGESA_SUCCESS) {
356 MemPtr->SpdDataStructure = (SPD_DEF_STRUCT *) AllocHeapParams.BufferPtr;
358 // Initialize SpdParam Structure
360 LibAmdMemCopy ((VOID *)&SpdParam, (VOID *)MemPtr, (UINTN)sizeof (SpdParam.StdHeader), &MemPtr->StdHeader);
362 // Populate SPDDataBuffer
364 SpdParam.MemData = MemPtr;
366 for (Socket = 0; Socket < (UINT16)MaxSockets; Socket++) {
367 MaxChannelsPerSocket = GetMaxChannelsPerSocket (PsoTable, Socket, &MemPtr->StdHeader);
368 SpdParam.SocketId = Socket;
369 for (Channel = 0; Channel < MaxChannelsPerSocket; Channel++) {
370 SpdParam.MemChannelId = Channel;
371 MaxDimmsPerChannel = GetMaxDimmsPerChannel (PsoTable, Socket, Channel);
372 for (Dimm = 0; Dimm < MaxDimmsPerChannel; Dimm++) {
373 SpdParam.DimmId = Dimm;
374 DimmSPDPtr = &(MemPtr->SpdDataStructure[DimmIndex++]);
375 SpdParam.Buffer = DimmSPDPtr->Data;
376 AGESA_TESTPOINT (TpProcMemBeforeAgesaReadSpd, &MemPtr->StdHeader);
377 AgesaStatus = AgesaReadSpd (0, &SpdParam);
378 AGESA_TESTPOINT (TpProcMemAfterAgesaReadSpd, &MemPtr->StdHeader);
379 if (AgesaStatus == AGESA_SUCCESS) {
380 DimmSPDPtr->DimmPresent = TRUE;
381 IDS_HDT_CONSOLE (MEM_FLOW, "SPD Socket %d Channel %d Dimm %d: %08x\n", Socket, Channel, Dimm, SpdParam.Buffer);
383 DimmSPDPtr->DimmPresent = FALSE;
389 PutEventLog (AGESA_FATAL, MEM_ERROR_HEAP_ALLOCATE_FOR_SPD, 0, 0, 0, 0, &MemPtr->StdHeader);
391 // Assert here if unable to allocate heap for SPDs