blob: eaf5b49ee6747cb3d4fd360a79476549f78ebedb [file] [log] [blame]
zbao7d94cf92012-07-02 14:19:14 +08001/* $NoKeywords:$ */
2/**
3 * @file
4 *
5 * mmflow.c
6 *
7 * Main Memory Flow Entrypoint file
8 *
9 * @xrefitem bom "File Content Label" "Release Content"
10 * @e project: AGESA
11 * @e sub-project: (Mem/Main)
12 * @e \$Revision: 63425 $ @e \$Date: 2011-12-22 11:24:10 -0600 (Thu, 22 Dec 2011) $
13 *
14 **/
15/*****************************************************************************
16*
Siyuan Wang641f00c2013-06-08 11:50:55 +080017 * Copyright (c) 2008 - 2012, Advanced Micro Devices, Inc.
18 * All rights reserved.
19 *
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.
30 *
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.
zbao7d94cf92012-07-02 14:19:14 +080041* ***************************************************************************
42*
43*/
44
45/*
46 *----------------------------------------------------------------------------
47 * MODULES USED
48 *
49 *----------------------------------------------------------------------------
50 */
51
52
53#include "AGESA.h"
54#include "amdlib.h"
55#include "AdvancedApi.h"
56#include "Ids.h"
57#include "cpuRegisters.h"
58#include "cpuServices.h"
59#include "GeneralServices.h"
60#include "cpuFamilyTranslation.h"
61#include "OptionMemory.h"
62#include "mm.h"
63#include "mn.h"
64#include "mt.h"
Mike Banonf7b410d2020-04-17 14:56:42 +030065#include "mtspd3.h"
zbao7d94cf92012-07-02 14:19:14 +080066#include "mu.h"
67#include "heapManager.h"
68#include "Filecode.h"
69CODE_GROUP (G1_PEICC)
70RDATA_GROUP (G1_PEICC)
71
72#define FILECODE PROC_MEM_MAIN_MMFLOW_FILECODE
73/* features */
74
75extern MEM_NB_SUPPORT memNBInstalled[];
76extern MEM_TECH_CONSTRUCTOR* memTechInstalled[];
77extern MEM_FEAT_BLOCK_MAIN MemFeatMain;
78extern MEM_FLOW_CFG* memFlowControlInstalled[];
79
80/*----------------------------------------------------------------------------
81 * DEFINITIONS AND MACROS
82 *
83 *----------------------------------------------------------------------------
84 */
85
86/*----------------------------------------------------------------------------
87 * TYPEDEFS AND STRUCTURES
88 *
89 *----------------------------------------------------------------------------
90 */
91
92/*----------------------------------------------------------------------------
93 * PROTOTYPES OF LOCAL FUNCTIONS
94 *
95 *----------------------------------------------------------------------------
96 */
97VOID
98STATIC
99MemSPDDataProcess (
100 IN OUT MEM_DATA_STRUCT *MemPtr
101 );
102
Mike Banonf7b410d2020-04-17 14:56:42 +0300103#if (CONFIG(CPU_AMD_AGESA_OPENSOURCE_MEM_CUSTOM))
104
105VOID
106STATIC
107AgesaCustomMemoryProfileSPD (
108 IN OUT UINT8 *Buffer
109 );
110
111#endif
112
zbao7d94cf92012-07-02 14:19:14 +0800113/*----------------------------------------------------------------------------
114 * EXPORTED FUNCTIONS
115 *
116 *----------------------------------------------------------------------------
117 */
118/* -----------------------------------------------------------------------------*/
119/**
120 *
121 *
122 * This function is the main memory configuration function for DR DDR3
123 *
124 * Requirements:
125 *
126 * Run-Time Requirements:
127 * 1. Complete Hypertransport Bus Configuration
128 * 2. AmdMemInitDataStructDef must be run to set default values
129 * 3. MSR bit to allow access to high PCI regs set on all nodes
130 * 4. BSP in Big Real Mode
131 * 5. Stack available
132 * 6. MCG_CTL=-1, MC4_EN=0 for all CPUs
133 * 7. MCi_STS from shutdown/warm reset recorded (if desired) prior to entry
134 * 8. All var MTRRs reset to zero
135 * 9. State of NB_CFG.DisDatMsk set properly on all CPUs
136 *
137 * @param[in,out] *MemPtr - Pointer to the MEM_DATA_STRUCT
138 *
139 * @return AGESA_STATUS
140 * - AGESA_ALERT
141 * - AGESA_FATAL
142 * - AGESA_SUCCESS
143 * - AGESA_WARNING
144 */
145AGESA_STATUS
146AmdMemAuto (
147 IN OUT MEM_DATA_STRUCT *MemPtr
148 )
149{
150 MEM_SHARED_DATA mmSharedData;
151 MEM_MAIN_DATA_BLOCK mmData;
152 MEM_NB_BLOCK *NBPtr;
153 MEM_TECH_BLOCK *TechPtr;
154 ALLOCATE_HEAP_PARAMS AllocHeapParams;
155 AGESA_STATUS Retval;
156 UINT8 i;
157 UINT8 Die;
158 UINT8 DieCount;
159 UINT8 Tab;
160 CPU_SPECIFIC_SERVICES *FamilySpecificServices;
161
162 ASSERT (MemPtr != NULL);
163
164 AGESA_TESTPOINT (TpProcMemAmdMemAuto, &MemPtr->StdHeader);
165
166 IDS_HDT_CONSOLE (MEM_FLOW, "MEM PARAMS:\n");
167 IDS_HDT_CONSOLE (MEM_FLOW, "\tBottomIo : %04x\n", MemPtr->ParameterListPtr->BottomIo);
168 IDS_HDT_CONSOLE (MEM_FLOW, "\tMemHoleRemap : %d\n", MemPtr->ParameterListPtr->MemHoleRemapping);
169 IDS_HDT_CONSOLE (MEM_FLOW, "\tLimitBelow1TB : %d\n", MemPtr->ParameterListPtr->LimitMemoryToBelow1Tb);
170 IDS_HDT_CONSOLE (MEM_FLOW, "\tUserTimingMode : %d\n", MemPtr->ParameterListPtr->UserTimingMode);
171 IDS_HDT_CONSOLE (MEM_FLOW, "\tMemClockValue : %d\n", MemPtr->ParameterListPtr->MemClockValue);
172 IDS_HDT_CONSOLE (MEM_FLOW, "\tBankIntlv : %d\n", MemPtr->ParameterListPtr->EnableBankIntlv);
173 IDS_HDT_CONSOLE (MEM_FLOW, "\tNodeIntlv : %d\n", MemPtr->ParameterListPtr->EnableNodeIntlv);
174 IDS_HDT_CONSOLE (MEM_FLOW, "\tChannelIntlv : %d\n", MemPtr->ParameterListPtr->EnableChannelIntlv);
175 IDS_HDT_CONSOLE (MEM_FLOW, "\tEccFeature : %d\n", MemPtr->ParameterListPtr->EnableEccFeature);
176 IDS_HDT_CONSOLE (MEM_FLOW, "\tPowerDown : %d\n", MemPtr->ParameterListPtr->EnablePowerDown);
177 IDS_HDT_CONSOLE (MEM_FLOW, "\tOnLineSpare : %d\n", MemPtr->ParameterListPtr->EnableOnLineSpareCtl);
178 IDS_HDT_CONSOLE (MEM_FLOW, "\tParity : %d\n", MemPtr->ParameterListPtr->EnableParity);
179 IDS_HDT_CONSOLE (MEM_FLOW, "\tBankSwizzle : %d\n", MemPtr->ParameterListPtr->EnableBankSwizzle);
180 IDS_HDT_CONSOLE (MEM_FLOW, "\tMemClr : %d\n", MemPtr->ParameterListPtr->EnableMemClr);
181 IDS_HDT_CONSOLE (MEM_FLOW, "\tUmaMode : %d\n", MemPtr->ParameterListPtr->UmaMode);
182 IDS_HDT_CONSOLE (MEM_FLOW, "\tUmaSize : %d\n", MemPtr->ParameterListPtr->UmaSize);
183 IDS_HDT_CONSOLE (MEM_FLOW, "\tMemRestoreCtl : %d\n", MemPtr->ParameterListPtr->MemRestoreCtl);
184 IDS_HDT_CONSOLE (MEM_FLOW, "\tSaveMemContextCtl : %d\n", MemPtr->ParameterListPtr->SaveMemContextCtl);
185 IDS_HDT_CONSOLE (MEM_FLOW, "\tExternalVrefCtl : %d\n", MemPtr->ParameterListPtr->ExternalVrefCtl );
186 IDS_HDT_CONSOLE (MEM_FLOW, "\tForceTrainMode : %d\n\n", MemPtr->ParameterListPtr->ForceTrainMode );
187
188 //----------------------------------------------------------------------------
189 // Get TSC rate, which will be used later in Wait10ns routine
190 //----------------------------------------------------------------------------
191 GetCpuServicesOfCurrentCore ((CONST CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, &MemPtr->StdHeader);
192 FamilySpecificServices->GetTscRate (FamilySpecificServices, &MemPtr->TscRate, &MemPtr->StdHeader);
193
194 //----------------------------------------------------------------------------
195 // Read In SPD Data
196 //----------------------------------------------------------------------------
197 AGESA_TESTPOINT (TpProcMemBeforeSpdProcessing, &MemPtr->StdHeader);
198 MemSPDDataProcess (MemPtr);
199
200 //----------------------------------------------------------------
201 // Initialize Main Data Block
202 //----------------------------------------------------------------
203 mmData.MemPtr = MemPtr;
204 mmData.mmSharedPtr = &mmSharedData;
205 LibAmdMemFill (&mmSharedData, 0, sizeof (mmSharedData), &MemPtr->StdHeader);
206 mmSharedData.DimmExcludeFlag = NORMAL;
207 mmSharedData.NodeIntlv.IsValid = FALSE;
208 //----------------------------------------------------------------
209 // Discover populated CPUs
210 //
211 //----------------------------------------------------------------
212 Retval = MemSocketScan (&mmData);
213 if (Retval == AGESA_FATAL) {
214 return Retval;
215 }
216 DieCount = mmData.DieCount;
217 //----------------------------------------------------------------
218 //
219 // Allocate Memory for NB and Tech Blocks
220 //
221 // NBPtr[Die]----+
222 // |
223 // V
224 // +---+---+---+---+---+---+---+---+
225 // | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | NB Blocks
226 // +---+---+---+---+---+---+---+---+
227 // | | | | | | | |
228 // | | | | | | | |
229 // v v v v v v v v
230 // +---+---+---+---+---+---+---+---+
231 // | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | Tech Blocks
232 // +---+---+---+---+---+---+---+---+
233 //
234 //
235 //----------------------------------------------------------------
236 AllocHeapParams.RequestedBufferSize = (DieCount * (sizeof (MEM_NB_BLOCK) + sizeof (MEM_TECH_BLOCK)));
237 AllocHeapParams.BufferHandle = AMD_MEM_AUTO_HANDLE;
238 AllocHeapParams.Persist = HEAP_LOCAL_CACHE;
239 if (AGESA_SUCCESS != HeapAllocateBuffer (&AllocHeapParams, &MemPtr->StdHeader)) {
240 ASSERT(FALSE); // NB and Tech Block Heap allocate error
241 return AGESA_FATAL;
242 }
243 NBPtr = (MEM_NB_BLOCK *)AllocHeapParams.BufferPtr;
244 TechPtr = (MEM_TECH_BLOCK *) (&NBPtr[DieCount]);
245 mmData.NBPtr = NBPtr;
246 mmData.TechPtr = TechPtr;
247
248 //----------------------------------------------------------------
249 // Create NB Blocks
250 //
251 //----------------------------------------------------------------
252 for (Die = 0 ; Die < DieCount ; Die++ ) {
253 i = 0;
254 while (memNBInstalled[i].MemConstructNBBlock != 0) {
255 if (memNBInstalled[i].MemConstructNBBlock (&NBPtr[Die], MemPtr, memNBInstalled[i].MemFeatBlock, &mmSharedData, Die) == TRUE) {
256 break;
257 }
258 i++;
259 }
260 // Couldn't find a NB which supported this family
261 if (memNBInstalled[i].MemConstructNBBlock == 0) {
262 return AGESA_FATAL;
263 }
264 }
265 //----------------------------------------------------------------
266 // Create Technology Blocks
267 //
268 //----------------------------------------------------------------
269 for (Die = 0 ; Die < DieCount ; Die++ ) {
270 i = 0;
271 while (memTechInstalled[i] != NULL) {
272 if (memTechInstalled[i] (&TechPtr[Die], &NBPtr[Die])) {
273 NBPtr[Die].TechPtr = &TechPtr[Die];
274 break;
275 }
276 i++;
277 }
278 // Couldn't find a Tech block which supported this family
279 if (memTechInstalled[i] == NULL) {
280 return AGESA_FATAL;
281 }
282 }
283 //----------------------------------------------------------------
284 //
285 // MEMORY INITIALIZATION TASKS
286 //
287 //----------------------------------------------------------------
288 i = 0;
289 while (memFlowControlInstalled[i] != NULL) {
290 Retval = memFlowControlInstalled[i] (&mmData);
291 if (MemPtr->IsFlowControlSupported == TRUE) {
292 break;
293 }
294 i++;
295 }
296
297 //----------------------------------------------------------------
298 // Deallocate NB register tables
299 //----------------------------------------------------------------
300 for (Tab = 0; Tab < NumberOfNbRegTables; Tab++) {
301 HeapDeallocateBuffer (GENERATE_MEM_HANDLE (ALLOC_NB_REG_TABLE, Tab, 0, 0), &MemPtr->StdHeader);
302 }
303
304 //----------------------------------------------------------------
305 // Check for errors and return
306 //----------------------------------------------------------------
307 AGESA_TESTPOINT (TpProcMemEnd, &MemPtr->StdHeader);
308 for (Die = 0; Die < DieCount; Die++) {
309 if (NBPtr[Die].MCTPtr->ErrCode > Retval) {
310 Retval = NBPtr[Die].MCTPtr->ErrCode;
311 }
312 }
313 return Retval;
314}
315
Mike Banonf7b410d2020-04-17 14:56:42 +0300316#if (CONFIG(CPU_AMD_AGESA_OPENSOURCE_MEM_CUSTOM))
317
318/* -----------------------------------------------------------------------------*/
319/**
320 *
321 *
322 * This function modifies a SPD buffer with the custom SPD values set up in coreboot's config.
323 *
324 * @param[in,out] *Buffer - Pointer to the UINT8
325 *
326 */
327
328VOID
329STATIC
330AgesaCustomMemoryProfileSPD (
331 IN OUT UINT8 *Buffer
332 )
333{
334 UINT16 Offset;
335 //
336 // Modify a SPD buffer.
337 //
338 Buffer[SPD_DIVIDENT] = CONFIG_CUSTOM_SPD_DIVIDENT;
339 Buffer[SPD_DIVISOR] = CONFIG_CUSTOM_SPD_DIVISOR;
340 Buffer[SPD_TCK] = CONFIG_CUSTOM_SPD_TCK;
341 Buffer[SPD_CASLO] = CONFIG_CUSTOM_SPD_CASLO;
342 Buffer[SPD_CASHI] = CONFIG_CUSTOM_SPD_CASHI;
343 Buffer[SPD_TAA] = CONFIG_CUSTOM_SPD_TAA;
344 Buffer[SPD_TWR] = CONFIG_CUSTOM_SPD_TWR;
345 Buffer[SPD_TRCD] = CONFIG_CUSTOM_SPD_TRCD;
346 Buffer[SPD_TRRD] = CONFIG_CUSTOM_SPD_TRRD;
347 Buffer[SPD_TRP] = CONFIG_CUSTOM_SPD_TRP;
348 //
349 // SPD_UPPER_TRC and SPD_UPPER_TRAS are the same index but different bits:
350 // SPD_UPPER_TRC - [7:4], SPD_UPPER_TRAS - [3:0].
351 //
352 Buffer[SPD_UPPER_TRAS] = (CONFIG_CUSTOM_SPD_UPPER_TRC << 4) + CONFIG_CUSTOM_SPD_UPPER_TRAS;
353 Buffer[SPD_TRAS] = CONFIG_CUSTOM_SPD_TRAS;
354 Buffer[SPD_TRC] = CONFIG_CUSTOM_SPD_TRC;
355 Buffer[SPD_TWTR] = CONFIG_CUSTOM_SPD_TWTR;
356 Buffer[SPD_TRTP] = CONFIG_CUSTOM_SPD_TRTP;
357 Buffer[SPD_UPPER_TFAW] = CONFIG_CUSTOM_SPD_UPPER_TFAW;
358 Buffer[SPD_TFAW] = CONFIG_CUSTOM_SPD_TFAW;
359 //
360 // Print a SPD buffer.
361 //
362 printk(BIOS_SPEW, "***** SPD BUFFER *****\n");
363 for (Offset = 0; Offset < 256; Offset++) {
364 printk(BIOS_SPEW, "Buffer[%d] = 0x%02X\n", Offset, Buffer[Offset]);
365 }
366 printk(BIOS_SPEW, "**********************\n");
367}
368
369#endif
zbao7d94cf92012-07-02 14:19:14 +0800370
371/* -----------------------------------------------------------------------------*/
372/**
373 *
374 *
375 * This function fills a default SPD buffer with SPD values for all DIMMs installed in the system
376 *
377 * The SPD Buffer is populated with a Socket-Channel-Dimm centric view of the Dimms. At this
378 * point, the Memory controller type is not known, and the platform BIOS does not know the anything
379 * about which DIMM is on which DCT. So the DCT relationship is abstracted from the arrangement
380 * of SPD information here. We use the utility functions GetSpdSocketIndex(), GetMaxChannelsPerSocket(),
381 * and GetMaxDimmsPerChannel() to Map the SPD data according to which Socket-relative channel the DIMMs
382 * are connected to. The functions rely on either the maximum values in the
383 * PlatformSpecificOverridingTable or if unspecified, the absolute maximums in AGESA.H.
384 *
385 * This mapping is translated in the Northbridge object Constructor and the Technology block constructor.
386 *
387 * @param[in,out] *MemPtr - Pointer to the MEM_DATA_STRUCT
388 *
389 */
390
391VOID
392STATIC
393MemSPDDataProcess (
394 IN OUT MEM_DATA_STRUCT *MemPtr
395 )
396{
397 UINT8 Socket;
398 UINT8 Channel;
399 UINT8 Dimm;
400 UINT8 DimmIndex;
401 UINT32 AgesaStatus;
402 UINT8 MaxSockets;
403 UINT8 MaxChannelsPerSocket;
404 UINT8 MaxDimmsPerChannel;
405 SPD_DEF_STRUCT *DimmSPDPtr;
406 PSO_TABLE *PsoTable;
407 ALLOCATE_HEAP_PARAMS AllocHeapParams;
408 AGESA_READ_SPD_PARAMS SpdParam;
409
410 ASSERT (MemPtr != NULL);
411 MaxSockets = (UINT8) (0x000000FF & GetPlatformNumberOfSockets ());
412 PsoTable = MemPtr->ParameterListPtr->PlatformMemoryConfiguration;
413 //
414 // Allocate heap for the table
415 //
416 AllocHeapParams.RequestedBufferSize = (GetSpdSocketIndex (PsoTable, MaxSockets, &MemPtr->StdHeader) * sizeof (SPD_DEF_STRUCT));
417 AllocHeapParams.BufferHandle = AMD_MEM_SPD_HANDLE;
418 AllocHeapParams.Persist = HEAP_LOCAL_CACHE;
419 if (HeapAllocateBuffer (&AllocHeapParams, &MemPtr->StdHeader) == AGESA_SUCCESS) {
420 MemPtr->SpdDataStructure = (SPD_DEF_STRUCT *) AllocHeapParams.BufferPtr;
421 //
422 // Initialize SpdParam Structure
423 //
424 LibAmdMemCopy ((VOID *)&SpdParam, (VOID *)MemPtr, (UINTN)sizeof (SpdParam.StdHeader), &MemPtr->StdHeader);
425 //
426 // Populate SPDDataBuffer
427 //
428 SpdParam.MemData = MemPtr;
429 DimmIndex = 0;
430 for (Socket = 0; Socket < (UINT16)MaxSockets; Socket++) {
431 MaxChannelsPerSocket = GetMaxChannelsPerSocket (PsoTable, Socket, &MemPtr->StdHeader);
432 SpdParam.SocketId = Socket;
433 for (Channel = 0; Channel < MaxChannelsPerSocket; Channel++) {
434 SpdParam.MemChannelId = Channel;
435 MaxDimmsPerChannel = GetMaxDimmsPerChannel (PsoTable, Socket, Channel);
436 for (Dimm = 0; Dimm < MaxDimmsPerChannel; Dimm++) {
437 SpdParam.DimmId = Dimm;
438 DimmSPDPtr = &(MemPtr->SpdDataStructure[DimmIndex++]);
439 SpdParam.Buffer = DimmSPDPtr->Data;
440 AGESA_TESTPOINT (TpProcMemBeforeAgesaReadSpd, &MemPtr->StdHeader);
441 AgesaStatus = AgesaReadSpd (0, &SpdParam);
442 AGESA_TESTPOINT (TpProcMemAfterAgesaReadSpd, &MemPtr->StdHeader);
443 if (AgesaStatus == AGESA_SUCCESS) {
444 DimmSPDPtr->DimmPresent = TRUE;
Angel Ponsb382b892021-05-09 16:11:30 +0200445 IDS_HDT_CONSOLE (MEM_FLOW, "SPD Socket %d Channel %d Dimm %d: %p\n", Socket, Channel, Dimm, SpdParam.Buffer);
Mike Banonf7b410d2020-04-17 14:56:42 +0300446 #if (CONFIG(CPU_AMD_AGESA_OPENSOURCE_MEM_CUSTOM))
447 AgesaCustomMemoryProfileSPD(SpdParam.Buffer);
448 #endif
zbao7d94cf92012-07-02 14:19:14 +0800449 } else {
450 DimmSPDPtr->DimmPresent = FALSE;
451 }
452 }
453 }
454 }
455 } else {
456 PutEventLog (AGESA_FATAL, MEM_ERROR_HEAP_ALLOCATE_FOR_SPD, 0, 0, 0, 0, &MemPtr->StdHeader);
457 //
458 // Assert here if unable to allocate heap for SPDs
459 //
460 IDS_ERROR_TRAP;
461 }
462}