blob: cf3942b08ecf1caf1f22f9c1a47284aafafaabe8 [file] [log] [blame]
Frank Vibrans2b4c8312011-02-14 18:30:54 +00001/* $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: 35735 $ @e \$Date: 2010-07-29 23:28:32 +0800 (Thu, 29 Jul 2010) $
13 *
14 **/
15/*
16 *****************************************************************************
17 *
18 * Copyright (c) 2011, Advanced Micro Devices, Inc.
19 * All rights reserved.
Edward O'Callaghan1542a6f2014-07-06 19:24:06 +100020 *
Frank Vibrans2b4c8312011-02-14 18:30:54 +000021 * Redistribution and use in source and binary forms, with or without
22 * modification, are permitted provided that the following conditions are met:
23 * * Redistributions of source code must retain the above copyright
24 * notice, this list of conditions and the following disclaimer.
25 * * Redistributions in binary form must reproduce the above copyright
26 * notice, this list of conditions and the following disclaimer in the
27 * documentation and/or other materials provided with the distribution.
Edward O'Callaghan1542a6f2014-07-06 19:24:06 +100028 * * Neither the name of Advanced Micro Devices, Inc. nor the names of
29 * its contributors may be used to endorse or promote products derived
Frank Vibrans2b4c8312011-02-14 18:30:54 +000030 * from this software without specific prior written permission.
Edward O'Callaghan1542a6f2014-07-06 19:24:06 +100031 *
Frank Vibrans2b4c8312011-02-14 18:30:54 +000032 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
34 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
35 * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
36 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
37 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
38 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
39 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
40 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
41 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Edward O'Callaghan1542a6f2014-07-06 19:24:06 +100042 *
Frank Vibrans2b4c8312011-02-14 18:30:54 +000043 * ***************************************************************************
44 *
45 */
46
47/*
48 *----------------------------------------------------------------------------
49 * MODULES USED
50 *
51 *----------------------------------------------------------------------------
52 */
53
54
55#include "AGESA.h"
56#include "amdlib.h"
57#include "Ids.h"
58#include "cpuRegisters.h"
59#include "cpuServices.h"
60#include "GeneralServices.h"
61#include "cpuFamilyTranslation.h"
62#include "OptionMemory.h"
efdesign9884cbce22011-08-04 12:09:17 -060063#include "AdvancedApi.h"
Frank Vibrans2b4c8312011-02-14 18:30:54 +000064#include "mm.h"
65#include "mn.h"
66#include "mt.h"
Mike Banonf7b410d2020-04-17 14:56:42 +030067#include "mtspd3.h"
Frank Vibrans2b4c8312011-02-14 18:30:54 +000068#include "mu.h"
69#include "heapManager.h"
70#include "Filecode.h"
71CODE_GROUP (G1_PEICC)
72RDATA_GROUP (G1_PEICC)
73
74#define FILECODE PROC_MEM_MAIN_MMFLOW_FILECODE
75/* features */
76
77extern MEM_NB_SUPPORT memNBInstalled[];
78extern MEM_TECH_CONSTRUCTOR* memTechInstalled[];
79extern MEM_FEAT_BLOCK_MAIN MemFeatMain;
80extern MEM_FLOW_CFG* memFlowControlInstalled[];
81
82/*----------------------------------------------------------------------------
83 * DEFINITIONS AND MACROS
84 *
85 *----------------------------------------------------------------------------
86 */
87
88/*----------------------------------------------------------------------------
89 * TYPEDEFS AND STRUCTURES
90 *
91 *----------------------------------------------------------------------------
92 */
93
94/*----------------------------------------------------------------------------
95 * PROTOTYPES OF LOCAL FUNCTIONS
96 *
97 *----------------------------------------------------------------------------
98 */
99VOID
100STATIC
101MemSPDDataProcess (
102 IN OUT MEM_DATA_STRUCT *MemPtr
103 );
104
Mike Banonf7b410d2020-04-17 14:56:42 +0300105#if (CONFIG(CPU_AMD_AGESA_OPENSOURCE_MEM_CUSTOM))
106
107VOID
108STATIC
109AgesaCustomMemoryProfileSPD (
110 IN OUT UINT8 *Buffer
111 );
112
113#endif
114
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000115/*----------------------------------------------------------------------------
116 * EXPORTED FUNCTIONS
117 *
118 *----------------------------------------------------------------------------
119 */
120/* -----------------------------------------------------------------------------*/
121/**
122 *
123 *
124 * This function is the main memory configuration function for DR DDR3
125 *
126 * Requirements:
127 *
128 * Run-Time Requirements:
129 * 1. Complete Hypertransport Bus Configuration
130 * 2. AmdMemInitDataStructDef must be run to set default values
131 * 3. MSR bit to allow access to high PCI regs set on all nodes
132 * 4. BSP in Big Real Mode
133 * 5. Stack available
134 * 6. MCG_CTL=-1, MC4_EN=0 for all CPUs
135 * 7. MCi_STS from shutdown/warm reset recorded (if desired) prior to entry
136 * 8. All var MTRRs reset to zero
137 * 9. State of NB_CFG.DisDatMsk set properly on all CPUs
138 *
139 * @param[in,out] *MemPtr - Pointer to the MEM_DATA_STRUCT
140 *
141 * @return AGESA_STATUS
142 * - AGESA_ALERT
143 * - AGESA_FATAL
144 * - AGESA_SUCCESS
145 * - AGESA_WARNING
146 */
147AGESA_STATUS
148AmdMemAuto (
149 IN OUT MEM_DATA_STRUCT *MemPtr
150 )
151{
152 MEM_SHARED_DATA mmSharedData;
153 MEM_MAIN_DATA_BLOCK mmData;
154 MEM_NB_BLOCK *NBPtr;
155 MEM_TECH_BLOCK *TechPtr;
156 ALLOCATE_HEAP_PARAMS AllocHeapParams;
157 AGESA_STATUS Retval;
158 UINT8 i;
159 UINT8 Die;
160 UINT8 DieCount;
161 CPU_SPECIFIC_SERVICES *FamilySpecificServices;
162
163 ASSERT (MemPtr != NULL);
164
165 AGESA_TESTPOINT (TpProcMemAmdMemAuto, &MemPtr->StdHeader);
166
167 IDS_HDT_CONSOLE (MEM_FLOW, "MEM PARAMS:\n");
168 IDS_HDT_CONSOLE (MEM_FLOW, "\tBottomIo : %04x\n", MemPtr->ParameterListPtr->BottomIo);
169 IDS_HDT_CONSOLE (MEM_FLOW, "\tMemHoleRemap : %d\n", MemPtr->ParameterListPtr->MemHoleRemapping);
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\n", MemPtr->ParameterListPtr->SaveMemContextCtl);
185
186 //----------------------------------------------------------------------------
187 // Get TSC rate, which will be used later in Wait10ns routine
188 //----------------------------------------------------------------------------
efdesign9884cbce22011-08-04 12:09:17 -0600189 GetCpuServicesOfCurrentCore ((const CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, &MemPtr->StdHeader);
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000190 FamilySpecificServices->GetTscRate (FamilySpecificServices, &MemPtr->TscRate, &MemPtr->StdHeader);
191
192 //----------------------------------------------------------------------------
193 // Read In SPD Data
194 //----------------------------------------------------------------------------
195 AGESA_TESTPOINT (TpProcMemBeforeSpdProcessing, &MemPtr->StdHeader);
196 MemSPDDataProcess (MemPtr);
197
198 //----------------------------------------------------------------
199 // Initialize Main Data Block
200 //----------------------------------------------------------------
201 mmData.MemPtr = MemPtr;
202 mmData.mmSharedPtr = &mmSharedData;
203 LibAmdMemFill (&mmSharedData, 0, sizeof (mmSharedData), &MemPtr->StdHeader);
204 mmSharedData.DimmExcludeFlag = NORMAL;
205 mmSharedData.NodeIntlv.IsValid = FALSE;
206 //----------------------------------------------------------------
207 // Discover populated CPUs
208 //
209 //----------------------------------------------------------------
210 Retval = MemSocketScan (&mmData);
211 if (Retval == AGESA_FATAL) {
212 return Retval;
213 }
214 DieCount = mmData.DieCount;
215 //----------------------------------------------------------------
216 //
217 // Allocate Memory for NB and Tech Blocks
218 //
219 // NBPtr[Die]----+
220 // |
221 // V
222 // +---+---+---+---+---+---+---+---+
223 // | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | NB Blocks
224 // +---+---+---+---+---+---+---+---+
225 // | | | | | | | |
226 // | | | | | | | |
227 // v v v v v v v v
228 // +---+---+---+---+---+---+---+---+
229 // | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | Tech Blocks
230 // +---+---+---+---+---+---+---+---+
231 //
232 //
233 //----------------------------------------------------------------
234 AllocHeapParams.RequestedBufferSize = (DieCount * (sizeof (MEM_NB_BLOCK) + sizeof (MEM_TECH_BLOCK)));
235 AllocHeapParams.BufferHandle = AMD_MEM_AUTO_HANDLE;
236 AllocHeapParams.Persist = HEAP_LOCAL_CACHE;
237 if (AGESA_SUCCESS != HeapAllocateBuffer (&AllocHeapParams, &MemPtr->StdHeader)) {
238 ASSERT(FALSE); // NB and Tech Block Heap allocate error
239 return AGESA_FATAL;
240 }
241 NBPtr = (MEM_NB_BLOCK *)AllocHeapParams.BufferPtr;
242 TechPtr = (MEM_TECH_BLOCK *) (&NBPtr[DieCount]);
243 mmData.NBPtr = NBPtr;
244 mmData.TechPtr = TechPtr;
245
246 //----------------------------------------------------------------
247 // Create NB Blocks
248 //
249 //----------------------------------------------------------------
250 for (Die = 0 ; Die < DieCount ; Die++ ) {
251 i = 0;
252 while (memNBInstalled[i].MemConstructNBBlock != 0) {
253 if (memNBInstalled[i].MemConstructNBBlock (&NBPtr[Die], MemPtr, memNBInstalled[i].MemFeatBlock, &mmSharedData, Die) == TRUE) {
254 break;
255 }
256 i++;
257 }
258 // Couldn't find a NB which supported this family
259 if (memNBInstalled[i].MemConstructNBBlock == 0) {
260 return AGESA_FATAL;
261 }
262 }
263 //----------------------------------------------------------------
264 // Create Technology Blocks
265 //
266 //----------------------------------------------------------------
267 for (Die = 0 ; Die < DieCount ; Die++ ) {
268 i = 0;
269 while (memTechInstalled[i] != NULL) {
270 if (memTechInstalled[i] (&TechPtr[Die], &NBPtr[Die])) {
271 NBPtr[Die].TechPtr = &TechPtr[Die];
272 break;
273 }
274 i++;
275 }
276 // Couldn't find a Tech block which supported this family
277 if (memTechInstalled[i] == NULL) {
278 return AGESA_FATAL;
279 }
280 }
281 //----------------------------------------------------------------
282 //
283 // MEMORY INITIALIZATION TASKS
284 //
285 //----------------------------------------------------------------
286 i = 0;
287 while (memFlowControlInstalled[i] != NULL) {
288 Retval = memFlowControlInstalled[i] (&mmData);
289 if (MemPtr->IsFlowControlSupported == TRUE) {
290 break;
291 }
292 i++;
293 }
294
295 //----------------------------------------------------------------
296 // Check for errors and return
297 //----------------------------------------------------------------
298 AGESA_TESTPOINT (TpProcMemEnd, &MemPtr->StdHeader);
299 for (Die = 0; Die < DieCount; Die++) {
300 if (NBPtr[Die].MCTPtr->ErrCode > Retval) {
301 Retval = NBPtr[Die].MCTPtr->ErrCode;
302 }
303 }
304 return Retval;
305}
306
Mike Banonf7b410d2020-04-17 14:56:42 +0300307#if (CONFIG(CPU_AMD_AGESA_OPENSOURCE_MEM_CUSTOM))
308
309/* -----------------------------------------------------------------------------*/
310/**
311 *
312 *
313 * This function modifies a SPD buffer with the custom SPD values set up in coreboot's config.
314 *
315 * @param[in,out] *Buffer - Pointer to the UINT8
316 *
317 */
318
319VOID
320STATIC
321AgesaCustomMemoryProfileSPD (
322 IN OUT UINT8 *Buffer
323 )
324{
325 UINT16 Offset;
326 //
327 // Modify a SPD buffer.
328 //
329 Buffer[SPD_DIVIDENT] = CONFIG_CUSTOM_SPD_DIVIDENT;
330 Buffer[SPD_DIVISOR] = CONFIG_CUSTOM_SPD_DIVISOR;
331 Buffer[SPD_TCK] = CONFIG_CUSTOM_SPD_TCK;
332 Buffer[SPD_CASLO] = CONFIG_CUSTOM_SPD_CASLO;
333 Buffer[SPD_CASHI] = CONFIG_CUSTOM_SPD_CASHI;
334 Buffer[SPD_TAA] = CONFIG_CUSTOM_SPD_TAA;
335 Buffer[SPD_TWR] = CONFIG_CUSTOM_SPD_TWR;
336 Buffer[SPD_TRCD] = CONFIG_CUSTOM_SPD_TRCD;
337 Buffer[SPD_TRRD] = CONFIG_CUSTOM_SPD_TRRD;
338 Buffer[SPD_TRP] = CONFIG_CUSTOM_SPD_TRP;
339 //
340 // SPD_UPPER_TRC and SPD_UPPER_TRAS are the same index but different bits:
341 // SPD_UPPER_TRC - [7:4], SPD_UPPER_TRAS - [3:0].
342 //
343 Buffer[SPD_UPPER_TRAS] = (CONFIG_CUSTOM_SPD_UPPER_TRC << 4) + CONFIG_CUSTOM_SPD_UPPER_TRAS;
344 Buffer[SPD_TRAS] = CONFIG_CUSTOM_SPD_TRAS;
345 Buffer[SPD_TRC] = CONFIG_CUSTOM_SPD_TRC;
346 Buffer[SPD_TWTR] = CONFIG_CUSTOM_SPD_TWTR;
347 Buffer[SPD_TRTP] = CONFIG_CUSTOM_SPD_TRTP;
348 Buffer[SPD_UPPER_TFAW] = CONFIG_CUSTOM_SPD_UPPER_TFAW;
349 Buffer[SPD_TFAW] = CONFIG_CUSTOM_SPD_TFAW;
350 //
351 // Print a SPD buffer.
352 //
353 printk(BIOS_SPEW, "***** SPD BUFFER *****\n");
354 for (Offset = 0; Offset < 256; Offset++) {
355 printk(BIOS_SPEW, "Buffer[%d] = 0x%02X\n", Offset, Buffer[Offset]);
356 }
357 printk(BIOS_SPEW, "**********************\n");
358}
359
360#endif
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000361
362/* -----------------------------------------------------------------------------*/
363/**
364 *
365 *
366 * This function fills a default SPD buffer with SPD values for all DIMMs installed in the system
367 *
368 * The SPD Buffer is populated with a Socket-Channel-Dimm centric view of the Dimms. At this
369 * point, the Memory controller type is not known, and the platform BIOS does not know the anything
370 * about which DIMM is on which DCT. So the DCT relationship is abstracted from the arrangement
371 * of SPD information here. We use the utility functions GetSpdSocketIndex(), GetMaxChannelsPerSocket(),
372 * and GetMaxDimmsPerChannel() to Map the SPD data according to which Socket-relative channel the DIMMs
373 * are connected to. The functions rely on either the maximum values in the
374 * PlatformSpecificOverridingTable or if unspecified, the absolute maximums in AGESA.H.
375 *
376 * This mapping is translated in the Northbridge object Constructor and the Technology block constructor.
377 *
378 * @param[in,out] *MemPtr - Pointer to the MEM_DATA_STRUCT
379 *
380 */
381
382VOID
383STATIC
384MemSPDDataProcess (
385 IN OUT MEM_DATA_STRUCT *MemPtr
386 )
387{
388 UINT8 Socket;
389 UINT8 Channel;
390 UINT8 Dimm;
391 UINT8 DimmIndex;
392 UINT32 AgesaStatus;
393 UINT8 MaxSockets;
394 UINT8 MaxChannelsPerSocket;
395 UINT8 MaxDimmsPerChannel;
396 SPD_DEF_STRUCT *DimmSPDPtr;
397 PSO_TABLE *PsoTable;
398 ALLOCATE_HEAP_PARAMS AllocHeapParams;
399 AGESA_READ_SPD_PARAMS SpdParam;
400
401 ASSERT (MemPtr != NULL);
402 MaxSockets = (UINT8) (0x000000FF & GetPlatformNumberOfSockets ());
403 PsoTable = MemPtr->ParameterListPtr->PlatformMemoryConfiguration;
404 //
405 // Allocate heap for the table
406 //
407 AllocHeapParams.RequestedBufferSize = (GetSpdSocketIndex (PsoTable, MaxSockets, &MemPtr->StdHeader) * sizeof (SPD_DEF_STRUCT));
408 AllocHeapParams.BufferHandle = AMD_MEM_SPD_HANDLE;
409 AllocHeapParams.Persist = HEAP_LOCAL_CACHE;
410 if (HeapAllocateBuffer (&AllocHeapParams, &MemPtr->StdHeader) == AGESA_SUCCESS) {
411 MemPtr->SpdDataStructure = (SPD_DEF_STRUCT *) AllocHeapParams.BufferPtr;
412 //
413 // Initialize SpdParam Structure
414 //
415 LibAmdMemCopy ((VOID *)&SpdParam, (VOID *)MemPtr, (UINTN)sizeof (SpdParam.StdHeader), &MemPtr->StdHeader);
416 //
417 // Populate SPDDataBuffer
418 //
419 SpdParam.MemData = MemPtr;
420 DimmIndex = 0;
421 for (Socket = 0; Socket < (UINT16)MaxSockets; Socket++) {
422 MaxChannelsPerSocket = GetMaxChannelsPerSocket (PsoTable, Socket, &MemPtr->StdHeader);
423 SpdParam.SocketId = Socket;
424 for (Channel = 0; Channel < MaxChannelsPerSocket; Channel++) {
425 SpdParam.MemChannelId = Channel;
426 MaxDimmsPerChannel = GetMaxDimmsPerChannel (PsoTable, Socket, Channel);
427 for (Dimm = 0; Dimm < MaxDimmsPerChannel; Dimm++) {
428 SpdParam.DimmId = Dimm;
429 DimmSPDPtr = &(MemPtr->SpdDataStructure[DimmIndex++]);
430 SpdParam.Buffer = DimmSPDPtr->Data;
431 AGESA_TESTPOINT (TpProcMemBeforeAgesaReadSpd, &MemPtr->StdHeader);
432 AgesaStatus = AgesaReadSpd (0, &SpdParam);
433 AGESA_TESTPOINT (TpProcMemAfterAgesaReadSpd, &MemPtr->StdHeader);
434 if (AgesaStatus == AGESA_SUCCESS) {
435 DimmSPDPtr->DimmPresent = TRUE;
436 IDS_HDT_CONSOLE (MEM_FLOW, "SPD Socket %d Channel %d Dimm %d: %08x\n", Socket, Channel, Dimm, SpdParam.Buffer);
Mike Banonf7b410d2020-04-17 14:56:42 +0300437 #if (CONFIG(CPU_AMD_AGESA_OPENSOURCE_MEM_CUSTOM))
438 AgesaCustomMemoryProfileSPD(SpdParam.Buffer);
439 #endif
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000440 } else {
441 DimmSPDPtr->DimmPresent = FALSE;
442 }
443 }
444 }
445 }
446 } else {
efdesign9884cbce22011-08-04 12:09:17 -0600447 PutEventLog (AGESA_FATAL, MEM_ERROR_HEAP_ALLOCATE_FOR_SPD, 0, 0, 0, 0, &MemPtr->StdHeader);
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000448 //
449 // Assert here if unable to allocate heap for SPDs
450 //
451 IDS_ERROR_TRAP;
452 }
453}