AGESA F15: AMD family15 AGESA code
[coreboot.git] / src / vendorcode / amd / agesa / f15 / Proc / Mem / NB / mnreg.c
1 /* $NoKeywords:$ */
2 /**
3  * @file
4  *
5  * mnreg.c
6  *
7  * Common Northbridge register access functions
8  *
9  * @xrefitem bom "File Content Label" "Release Content"
10  * @e project: AGESA
11  * @e sub-project: (Mem/NB/)
12  * @e \$Revision: 56279 $ @e \$Date: 2011-07-11 13:11:28 -0600 (Mon, 11 Jul 2011) $
13  *
14  **/
15 /*****************************************************************************
16 *
17 * Copyright (C) 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.
41 *
42 * ***************************************************************************
43 *
44 */
45 /*
46  *----------------------------------------------------------------------------
47  *                                MODULES USED
48  *
49  *----------------------------------------------------------------------------
50  */
51
52
53
54 #include "AGESA.h"
55 #include "AdvancedApi.h"
56 #include "amdlib.h"
57 #include "Ids.h"
58 #include "mm.h"
59 #include "mn.h"
60 #include "merrhdl.h"
61 #include "heapManager.h"
62 #include "Filecode.h"
63 #include "GeneralServices.h"
64 CODE_GROUP (G1_PEICC)
65 RDATA_GROUP (G2_PEI)
66
67 #define FILECODE PROC_MEM_NB_MNREG_FILECODE
68
69
70 /*----------------------------------------------------------------------------
71  *                          DEFINITIONS AND MACROS
72  *
73  *----------------------------------------------------------------------------
74  */
75
76 /*----------------------------------------------------------------------------
77  *                           TYPEDEFS AND STRUCTURES
78  *
79  *----------------------------------------------------------------------------
80  */
81
82 /*----------------------------------------------------------------------------
83  *                        PROTOTYPES OF LOCAL FUNCTIONS
84  *
85  *----------------------------------------------------------------------------
86  */
87
88 /*----------------------------------------------------------------------------
89  *                            EXPORTED FUNCTIONS
90  *
91  *----------------------------------------------------------------------------
92  */
93
94 /* -----------------------------------------------------------------------------*/
95 /**
96  *
97  *
98  *   This function sets the current DCT to work on.
99  *   Should be called before accessing a certain DCT
100  *   All data structures will be updated to point to the current DCT
101  *
102  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
103  *     @param[in]   Dct - ID of the target DCT
104  *
105  */
106
107 VOID
108 MemNSwitchDCTNb (
109   IN OUT   MEM_NB_BLOCK *NBPtr,
110   IN       UINT8 Dct
111   )
112 {
113   ASSERT (NBPtr->DctCount > Dct);
114   //
115   // Set the DctCfgSel to new DCT
116   //
117   NBPtr->FamilySpecificHook[DCTSelectSwitch] (NBPtr, &Dct);
118   NBPtr->Dct = Dct;
119   NBPtr->MCTPtr->Dct = NBPtr->Dct;
120   NBPtr->DCTPtr = &(NBPtr->MCTPtr->DctData[NBPtr->Dct]);
121   NBPtr->PsPtr = &(NBPtr->PSBlock[NBPtr->Dct]);
122   NBPtr->DctCachePtr = &(NBPtr->DctCache[NBPtr->Dct]);
123
124   MemNSwitchChannelNb (NBPtr, NBPtr->Channel);
125 }
126
127 /* -----------------------------------------------------------------------------*/
128 /**
129  *
130  *     This function is used by families that use a separate DctCfgSel bit to
131  *     select the current DCT which will be accessed by function 2.
132  *     NOTE:  This function must be called BEFORE the NBPtr->Dct variable is
133  *     updated.
134  *
135  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
136  *     @param[in]       *Dct     - Pointer to ID of the target DCT
137  *
138  */
139
140 BOOLEAN
141 MemNDctCfgSelectUnb (
142   IN OUT   MEM_NB_BLOCK *NBPtr,
143   IN       VOID *Dct
144   )
145 {
146   //
147   // Sanity check the current DctCfgSel setting
148   //
149   ASSERT (NBPtr->Dct == NBPtr->GetBitField (NBPtr, BFDctCfgSel));
150   //
151   // Set the DctCfgSel to new DCT
152   //
153   NBPtr->SetBitField (NBPtr, BFDctCfgSel, *(UINT8*)Dct);
154
155   return TRUE;
156 }
157
158
159 /* -----------------------------------------------------------------------------*/
160 /**
161  *
162  *
163  *   This function sets the current channel to work on.
164  *   Should be called before accessing a certain channel
165  *   All data structures will be updated to point to the current channel
166  *
167  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
168  *     @param[in]   Channel - ID of the target channel
169  *
170  */
171
172 VOID
173 MemNSwitchChannelNb (
174   IN OUT   MEM_NB_BLOCK *NBPtr,
175   IN       UINT8 Channel
176   )
177 {
178   NBPtr->Channel = Channel ? 1 : 0;
179   NBPtr->ChannelPtr = &(NBPtr->DCTPtr->ChData[NBPtr->Channel]);
180 }
181
182 /* -----------------------------------------------------------------------------*/
183 /**
184  *
185  *
186  *   This function gets a bit field from PCI register
187  *
188  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
189  *     @param[in]   FieldName - Field name
190  *
191  *     @return      Bit field value
192  */
193
194 UINT32
195 MemNGetBitFieldNb (
196   IN OUT   MEM_NB_BLOCK *NBPtr,
197   IN       BIT_FIELD_NAME FieldName
198   )
199 {
200   UINT32 Value;
201
202   ASSERT (FieldName < BFEndOfList);
203   Value = NBPtr->MemNCmnGetSetFieldNb (NBPtr, 0, FieldName, 0);
204   return Value;
205 }
206
207 /* -----------------------------------------------------------------------------*/
208 /**
209  *
210  *
211  *   This function sets a bit field from PCI register
212  *
213  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
214  *     @param[in]   FieldName - Field name
215  *     @param[in]   Field - Value to be stored in PCT register
216  *
217  */
218
219 VOID
220 MemNSetBitFieldNb (
221   IN OUT   MEM_NB_BLOCK *NBPtr,
222   IN       BIT_FIELD_NAME FieldName,
223   IN       UINT32 Field
224   )
225 {
226   ASSERT (FieldName < BFEndOfList);
227   NBPtr->MemNCmnGetSetFieldNb (NBPtr, 1, FieldName, Field);
228 }
229
230 /* -----------------------------------------------------------------------------*/
231 /**
232  *
233  *  Check if bitfields of all enabled DCTs on a die have the expected value. Ignore
234  *  DCTs that are disabled.
235  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
236  *     @param[in]   FieldName - Bit Field name
237  *     @param[in]   Field - Value to be checked
238  *
239  *     @return          TRUE -  All enabled DCTs have the expected value on the bitfield.
240  *     @return          FALSE - Not all enabled DCTs have the expected value on the bitfield.
241  *
242  * ----------------------------------------------------------------------------
243  */
244 BOOLEAN
245 MemNBrdcstCheckNb (
246   IN OUT   MEM_NB_BLOCK *NBPtr,
247   IN       BIT_FIELD_NAME FieldName,
248   IN       UINT32 Field
249   )
250 {
251   UINT8 Dct;
252   UINT8 CurrentDCT;
253   Dct = NBPtr->Dct;
254   for (CurrentDCT = 0; CurrentDCT < NBPtr->DctCount; CurrentDCT++) {
255     MemNSwitchDCTNb (NBPtr, CurrentDCT);
256     if ((NBPtr->DCTPtr->Timings.DctMemSize != 0) && !((CurrentDCT == 1) && NBPtr->Ganged)) {
257       if (MemNGetBitFieldNb (NBPtr, FieldName) != Field) {
258         MemNSwitchDCTNb (NBPtr, Dct);
259         return FALSE;
260       }
261     }
262   }
263   MemNSwitchDCTNb (NBPtr, Dct);
264   return TRUE;
265 }
266
267 /* -----------------------------------------------------------------------------*/
268 /**
269  *
270  *  Set bitfields of all enabled DCTs on a die to a value. Ignore
271  *  DCTs that are disabled.
272  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
273  *     @param[in]   FieldName - Bit Field name
274  *     @param[in]   Field - Value to be set
275  *
276  * ----------------------------------------------------------------------------
277  */
278 VOID
279 MemNBrdcstSetNb (
280   IN OUT   MEM_NB_BLOCK *NBPtr,
281   IN       BIT_FIELD_NAME FieldName,
282   IN       UINT32 Field
283   )
284 {
285   UINT8 Dct;
286   UINT8 CurrentDCT;
287   Dct = NBPtr->Dct;
288   for (CurrentDCT = 0; CurrentDCT < NBPtr->DctCount; CurrentDCT++) {
289     MemNSwitchDCTNb (NBPtr, CurrentDCT);
290     if ((NBPtr->DCTPtr->Timings.DctMemSize != 0) && !((CurrentDCT == 1) && NBPtr->Ganged)) {
291       MemNSetBitFieldNb (NBPtr, FieldName, Field);
292     }
293   }
294   MemNSwitchDCTNb (NBPtr, Dct);
295 }
296
297 /*-----------------------------------------------------------------------------*/
298 /**
299  *      This function calculates the memory channel index relative to the
300  *      socket, taking the Die number, the Dct, and the channel.
301  *
302  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
303  *     @param[in] Dct
304  *     @param[in] Channel
305  *
306  */
307 UINT8
308 MemNGetSocketRelativeChannelNb (
309   IN OUT   MEM_NB_BLOCK *NBPtr,
310   IN       UINT8 Dct,
311   IN       UINT8 Channel
312   )
313 {
314   return ((NBPtr->MCTPtr->DieId * NBPtr->DctCount) + Dct);
315 }
316
317 /* -----------------------------------------------------------------------------*/
318 /**
319  *
320  *  Poll a bitfield. If the bitfield does not get set to the target value within
321  *  specified microseconds, it times out.
322  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
323  *     @param[in]   FieldName - Bit Field name
324  *     @param[in]   Field - Value to be set
325  *     @param[in]   MicroSecond - Number of microsecond to wait
326  *     @param[in]   IfBroadCast - Need to broadcast to both DCT or not
327  *
328  * ----------------------------------------------------------------------------
329  */
330 VOID
331 MemNPollBitFieldNb (
332   IN OUT   MEM_NB_BLOCK *NBPtr,
333   IN       BIT_FIELD_NAME FieldName,
334   IN       UINT32 Field,
335   IN       UINT32 MicroSecond,
336   IN       BOOLEAN IfBroadCast
337   )
338 {
339   BOOLEAN ErrorRecovery;
340   BOOLEAN IgnoreErr;
341   UINT8 ExcludeDCT;
342   UINT16 ExcludeChipSelMask;
343   UINT32 EventInfo;
344   UINT64 InitTSC;
345   UINT64 CurrentTSC;
346   UINT64 TimeOut;
347   AGESA_STATUS EventClass;
348   MEM_DATA_STRUCT *MemPtr;
349   DIE_STRUCT *MCTPtr;
350   BOOLEAN TimeoutEn;
351
352   MemPtr = NBPtr->MemPtr;
353   MCTPtr = NBPtr->MCTPtr;
354   ExcludeDCT = EXCLUDE_ALL_DCT;
355   ExcludeChipSelMask = EXCLUDE_ALL_CHIPSEL;
356   TimeoutEn = TRUE;
357   IDS_TIMEOUT_CTL (&TimeoutEn);
358
359   CurrentTSC = 0;
360   LibAmdMsrRead (TSC, &InitTSC, &MemPtr->StdHeader);
361   TimeOut = InitTSC + ((UINT64) MicroSecond * MemPtr->TscRate);
362
363   while ((CurrentTSC < TimeOut) || !TimeoutEn) {
364     if (IfBroadCast) {
365       if (NBPtr->BrdcstCheck (NBPtr, FieldName, Field)) {
366         break;
367       }
368     } else {
369       if (MemNGetBitFieldNb (NBPtr, FieldName) == Field) {
370         break;
371       }
372     }
373     LibAmdMsrRead (TSC, &CurrentTSC, &MemPtr->StdHeader);
374   }
375
376   if ((CurrentTSC >= TimeOut) && TimeoutEn) {
377     ErrorRecovery = TRUE;
378     IgnoreErr = FALSE;
379     IDS_OPTION_HOOK (IDS_MEM_ERROR_RECOVERY, &ErrorRecovery, &MemPtr->StdHeader);
380     IDS_OPTION_HOOK (IDS_MEM_IGNORE_ERROR, &IgnoreErr, &MemPtr->StdHeader);
381
382     // Default event class
383     // If different event class is needed in one entry, override it.
384     EventClass = AGESA_ERROR;
385     switch (FieldName) {
386     case BFDramEnabled:
387       EventInfo = MEM_ERROR_DRAM_ENABLED_TIME_OUT;
388       IDS_HDT_CONSOLE (MEM_FLOW, "\tDramEnabled bitfield times out.\n");
389       ASSERT (ErrorRecovery || IgnoreErr);
390       break;
391     case BFDctAccessDone:
392       EventInfo = MEM_ERROR_DCT_ACCESS_DONE_TIME_OUT;
393       ExcludeDCT = NBPtr->Dct;
394       IDS_HDT_CONSOLE (MEM_FLOW, "\tDctAccessDone bitfield times out.\n");
395       ASSERT (ErrorRecovery || IgnoreErr);
396       break;
397     case BFSendCtrlWord:
398       EventInfo = MEM_ERROR_SEND_CTRL_WORD_TIME_OUT;
399       ExcludeDCT = NBPtr->Dct;
400       IDS_HDT_CONSOLE (MEM_FLOW, "\tSendCtrlWord bitfield times out.\n");
401       ASSERT (ErrorRecovery || IgnoreErr);
402       break;
403     case BFPrefDramTrainMode:
404       EventInfo = MEM_ERROR_PREF_DRAM_TRAIN_MODE_TIME_OUT;
405       ExcludeDCT = NBPtr->Dct;
406       IDS_HDT_CONSOLE (MEM_FLOW, "\tPrefDramTrainMode bitfield times out.\n");
407       ASSERT (ErrorRecovery || IgnoreErr);
408       break;
409     case BFEnterSelfRef:
410       EventInfo = MEM_ERROR_ENTER_SELF_REF_TIME_OUT;
411       IDS_HDT_CONSOLE (MEM_FLOW, "\tEnterSelfRef bitfield times out.\n");
412       ASSERT (ErrorRecovery || IgnoreErr);
413       break;
414     case BFFreqChgInProg:
415       EventInfo = MEM_ERROR_FREQ_CHG_IN_PROG_TIME_OUT;
416       ExcludeDCT = NBPtr->Dct;
417       IDS_HDT_CONSOLE (MEM_FLOW, "\tFreqChgInProg bitfield times out.\n");
418       ASSERT (ErrorRecovery || IgnoreErr);
419       break;
420     case BFExitSelfRef:
421       EventInfo = MEM_ERROR_EXIT_SELF_REF_TIME_OUT;
422       IDS_HDT_CONSOLE (MEM_FLOW, "\tExitSelfRef bitfield times out.\n");
423       ASSERT (ErrorRecovery || IgnoreErr);
424       break;
425     case BFSendMrsCmd:
426       EventInfo = MEM_ERROR_SEND_MRS_CMD_TIME_OUT;
427       ExcludeDCT = NBPtr->Dct;
428       IDS_HDT_CONSOLE (MEM_FLOW, "\tSendMrsCmd bitfield times out.\n");
429       ASSERT (ErrorRecovery || IgnoreErr);
430       break;
431     case BFSendZQCmd:
432       EventInfo = MEM_ERROR_SEND_ZQ_CMD_TIME_OUT;
433       ExcludeDCT = NBPtr->Dct;
434       IDS_HDT_CONSOLE (MEM_FLOW, "\tSendZQCmd bitfield times out.\n");
435       ASSERT (ErrorRecovery || IgnoreErr);
436       break;
437     case BFDctExtraAccessDone:
438       EventInfo = MEM_ERROR_DCT_EXTRA_ACCESS_DONE_TIME_OUT;
439       ExcludeDCT = NBPtr->Dct;
440       IDS_HDT_CONSOLE (MEM_FLOW, "\tDctExtraAccessDone bitfield times out.\n");
441       ASSERT (ErrorRecovery || IgnoreErr);
442       break;
443     case BFMemClrBusy:
444       EventInfo = MEM_ERROR_MEM_CLR_BUSY_TIME_OUT;
445       IDS_HDT_CONSOLE (MEM_FLOW, "\tMemClrBusy bitfield times out.\n");
446       ASSERT (ErrorRecovery || IgnoreErr);
447       break;
448     case BFMemCleared:
449       EventInfo = MEM_ERROR_MEM_CLEARED_TIME_OUT;
450       IDS_HDT_CONSOLE (MEM_FLOW, "\tMemCleared bitfield times out.\n");
451       ASSERT (ErrorRecovery || IgnoreErr);
452       break;
453     case BFFlushWr:
454       EventInfo = MEM_ERROR_FLUSH_WR_TIME_OUT;
455       ExcludeDCT = NBPtr->Dct;
456       IDS_HDT_CONSOLE (MEM_FLOW, "\tFlushWr bitfield times out.\n");
457       ASSERT (ErrorRecovery || IgnoreErr);
458       break;
459     default:
460       EventClass = 0;
461       EventInfo = 0;
462       IDS_ERROR_TRAP;
463     }
464
465     PutEventLog (EventClass, EventInfo, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &MemPtr->StdHeader);
466     SetMemError (EventClass, MCTPtr);
467     if (!MemPtr->ErrorHandling (MCTPtr, ExcludeDCT, ExcludeChipSelMask, &MemPtr->StdHeader)) {
468       ASSERT (FALSE);
469     }
470   }
471 }
472
473 /* -----------------------------------------------------------------------------*/
474 /**
475  *
476  *
477  *     This function changes memory Pstate context
478  *
479  *     @param[in,out]  *NBPtr     - Pointer to the MEM_NB_BLOCK
480  *     @param[in]      MemPstate  - Target Memory Pstate
481  *
482  *     @return    TRUE
483  * ----------------------------------------------------------------------------
484  */
485 VOID
486 MemNChangeMemPStateContextNb (
487   IN OUT   MEM_NB_BLOCK *NBPtr,
488   IN       MEM_PSTATE MemPstate
489   )
490 {
491   UINT8 PSMasterChannel;
492   UINT8 Dct;
493
494   ASSERT ((MemPstate == 0) || (MemPstate == 1));
495   ASSERT (NBPtr->MemPstate == ((MemNGetBitFieldNb (NBPtr, BFMemPsSel) == 0) ? MEMORY_PSTATE0 : MEMORY_PSTATE1));
496
497   IDS_HDT_CONSOLE (MEM_FLOW, "\nGo to Memory Pstate Conext %d\n", MemPstate);
498   Dct = NBPtr->Dct;
499   MemNSwitchDCTNb (NBPtr, 0);
500   // Figure out what is the master channel
501   PSMasterChannel = (UINT8) (MemNGetBitFieldNb (NBPtr, BFPhyPSMasterChannel) >> 8);
502
503   // Switch to the master channel to change PStateToAccess
504   // PStateToAccess is only effective on the master channel
505   MemNSwitchDCTNb (NBPtr, PSMasterChannel);
506   MemNSetBitFieldNb (NBPtr, BFMemPsSel, MemPstate);
507   MemNSetBitFieldNb (NBPtr, BFPStateToAccess, MemPstate << 8);
508
509   NBPtr->MemPstate = (MemPstate == 0) ? MEMORY_PSTATE0 : MEMORY_PSTATE1;
510   MemNSwitchDCTNb (NBPtr, Dct);
511 }
512
513 /* -----------------------------------------------------------------------------*/
514 /**
515  *
516  *   This function allocates buffer for NB register table
517  *
518  *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
519  *     @param[in]       Handle   - Handle for heap allocation for NBRegTable
520  *
521  *     @return      TRUE  - Successfully allocates buffer the first time
522  *     @return      FALSE - Buffer already allocated or fails to allocate
523  */
524
525 BOOLEAN
526 MemNAllocateNBRegTableNb (
527   IN OUT   MEM_NB_BLOCK *NBPtr,
528   IN       NB_REG_TAB_HANDLE  Handle
529   )
530 {
531   ALLOCATE_HEAP_PARAMS AllocHeapParams;
532   LOCATE_HEAP_PTR LocHeap;
533
534   // If NBRegTable for this family exists, use it
535   LocHeap.BufferHandle = GENERATE_MEM_HANDLE (ALLOC_NB_REG_TABLE, Handle, 0, 0);
536   if (HeapLocateBuffer (&LocHeap, &(NBPtr->MemPtr->StdHeader)) == AGESA_SUCCESS) {
537     NBPtr->NBRegTable = (TSEFO *) LocHeap.BufferPtr;
538     return FALSE;
539   }
540
541   // Allocate new buffer for NBRegTable if it has not been allocated
542   AllocHeapParams.RequestedBufferSize = sizeof (TSEFO) * BFEndOfList;
543   AllocHeapParams.BufferHandle = GENERATE_MEM_HANDLE (ALLOC_NB_REG_TABLE, Handle, 0, 0);
544   AllocHeapParams.Persist = HEAP_SYSTEM_MEM;
545   if (AGESA_SUCCESS != HeapAllocateBuffer (&AllocHeapParams, &(NBPtr->MemPtr->StdHeader))) {
546     ASSERT(FALSE); // NB and Tech Block Heap allocate error
547     return FALSE;
548   }
549   NBPtr->NBRegTable = (TSEFO *)AllocHeapParams.BufferPtr;
550   return TRUE;
551 }