7 * Common Northbridge register access functions
9 * @xrefitem bom "File Content Label" "Release Content"
11 * @e sub-project: (Mem/NB/)
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 * ***************************************************************************
46 *----------------------------------------------------------------------------
49 *----------------------------------------------------------------------------
55 #include "AdvancedApi.h"
61 #include "heapManager.h"
63 #include "GeneralServices.h"
67 #define FILECODE PROC_MEM_NB_MNREG_FILECODE
70 /*----------------------------------------------------------------------------
71 * DEFINITIONS AND MACROS
73 *----------------------------------------------------------------------------
76 /*----------------------------------------------------------------------------
77 * TYPEDEFS AND STRUCTURES
79 *----------------------------------------------------------------------------
82 /*----------------------------------------------------------------------------
83 * PROTOTYPES OF LOCAL FUNCTIONS
85 *----------------------------------------------------------------------------
88 /*----------------------------------------------------------------------------
91 *----------------------------------------------------------------------------
94 /* -----------------------------------------------------------------------------*/
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
102 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
103 * @param[in] Dct - ID of the target DCT
109 IN OUT MEM_NB_BLOCK *NBPtr,
113 ASSERT (NBPtr->DctCount > Dct);
115 // Set the DctCfgSel to new DCT
117 NBPtr->FamilySpecificHook[DCTSelectSwitch] (NBPtr, &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]);
124 MemNSwitchChannelNb (NBPtr, NBPtr->Channel);
127 /* -----------------------------------------------------------------------------*/
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
135 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
136 * @param[in] *Dct - Pointer to ID of the target DCT
141 MemNDctCfgSelectUnb (
142 IN OUT MEM_NB_BLOCK *NBPtr,
147 // Sanity check the current DctCfgSel setting
149 ASSERT (NBPtr->Dct == NBPtr->GetBitField (NBPtr, BFDctCfgSel));
151 // Set the DctCfgSel to new DCT
153 NBPtr->SetBitField (NBPtr, BFDctCfgSel, *(UINT8*)Dct);
159 /* -----------------------------------------------------------------------------*/
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
167 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
168 * @param[in] Channel - ID of the target channel
173 MemNSwitchChannelNb (
174 IN OUT MEM_NB_BLOCK *NBPtr,
178 NBPtr->Channel = Channel ? 1 : 0;
179 NBPtr->ChannelPtr = &(NBPtr->DCTPtr->ChData[NBPtr->Channel]);
182 /* -----------------------------------------------------------------------------*/
186 * This function gets a bit field from PCI register
188 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
189 * @param[in] FieldName - Field name
191 * @return Bit field value
196 IN OUT MEM_NB_BLOCK *NBPtr,
197 IN BIT_FIELD_NAME FieldName
202 ASSERT (FieldName < BFEndOfList);
203 Value = NBPtr->MemNCmnGetSetFieldNb (NBPtr, 0, FieldName, 0);
207 /* -----------------------------------------------------------------------------*/
211 * This function sets a bit field from PCI register
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
221 IN OUT MEM_NB_BLOCK *NBPtr,
222 IN BIT_FIELD_NAME FieldName,
226 ASSERT (FieldName < BFEndOfList);
227 NBPtr->MemNCmnGetSetFieldNb (NBPtr, 1, FieldName, Field);
230 /* -----------------------------------------------------------------------------*/
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
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.
242 * ----------------------------------------------------------------------------
246 IN OUT MEM_NB_BLOCK *NBPtr,
247 IN BIT_FIELD_NAME FieldName,
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);
263 MemNSwitchDCTNb (NBPtr, Dct);
267 /* -----------------------------------------------------------------------------*/
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
276 * ----------------------------------------------------------------------------
280 IN OUT MEM_NB_BLOCK *NBPtr,
281 IN BIT_FIELD_NAME FieldName,
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);
294 MemNSwitchDCTNb (NBPtr, Dct);
297 /*-----------------------------------------------------------------------------*/
299 * This function calculates the memory channel index relative to the
300 * socket, taking the Die number, the Dct, and the channel.
302 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
308 MemNGetSocketRelativeChannelNb (
309 IN OUT MEM_NB_BLOCK *NBPtr,
314 return ((NBPtr->MCTPtr->DieId * NBPtr->DctCount) + Dct);
317 /* -----------------------------------------------------------------------------*/
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
328 * ----------------------------------------------------------------------------
332 IN OUT MEM_NB_BLOCK *NBPtr,
333 IN BIT_FIELD_NAME FieldName,
335 IN UINT32 MicroSecond,
336 IN BOOLEAN IfBroadCast
339 BOOLEAN ErrorRecovery;
342 UINT16 ExcludeChipSelMask;
347 AGESA_STATUS EventClass;
348 MEM_DATA_STRUCT *MemPtr;
352 MemPtr = NBPtr->MemPtr;
353 MCTPtr = NBPtr->MCTPtr;
354 ExcludeDCT = EXCLUDE_ALL_DCT;
355 ExcludeChipSelMask = EXCLUDE_ALL_CHIPSEL;
357 IDS_TIMEOUT_CTL (&TimeoutEn);
360 LibAmdMsrRead (TSC, &InitTSC, &MemPtr->StdHeader);
361 TimeOut = InitTSC + ((UINT64) MicroSecond * MemPtr->TscRate);
363 while ((CurrentTSC < TimeOut) || !TimeoutEn) {
365 if (NBPtr->BrdcstCheck (NBPtr, FieldName, Field)) {
369 if (MemNGetBitFieldNb (NBPtr, FieldName) == Field) {
373 LibAmdMsrRead (TSC, &CurrentTSC, &MemPtr->StdHeader);
376 if ((CurrentTSC >= TimeOut) && TimeoutEn) {
377 ErrorRecovery = TRUE;
379 IDS_OPTION_HOOK (IDS_MEM_ERROR_RECOVERY, &ErrorRecovery, &MemPtr->StdHeader);
380 IDS_OPTION_HOOK (IDS_MEM_IGNORE_ERROR, &IgnoreErr, &MemPtr->StdHeader);
382 // Default event class
383 // If different event class is needed in one entry, override it.
384 EventClass = AGESA_ERROR;
387 EventInfo = MEM_ERROR_DRAM_ENABLED_TIME_OUT;
388 IDS_HDT_CONSOLE (MEM_FLOW, "\tDramEnabled bitfield times out.\n");
389 ASSERT (ErrorRecovery || IgnoreErr);
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);
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);
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);
410 EventInfo = MEM_ERROR_ENTER_SELF_REF_TIME_OUT;
411 IDS_HDT_CONSOLE (MEM_FLOW, "\tEnterSelfRef bitfield times out.\n");
412 ASSERT (ErrorRecovery || IgnoreErr);
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);
421 EventInfo = MEM_ERROR_EXIT_SELF_REF_TIME_OUT;
422 IDS_HDT_CONSOLE (MEM_FLOW, "\tExitSelfRef bitfield times out.\n");
423 ASSERT (ErrorRecovery || IgnoreErr);
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);
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);
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);
444 EventInfo = MEM_ERROR_MEM_CLR_BUSY_TIME_OUT;
445 IDS_HDT_CONSOLE (MEM_FLOW, "\tMemClrBusy bitfield times out.\n");
446 ASSERT (ErrorRecovery || IgnoreErr);
449 EventInfo = MEM_ERROR_MEM_CLEARED_TIME_OUT;
450 IDS_HDT_CONSOLE (MEM_FLOW, "\tMemCleared bitfield times out.\n");
451 ASSERT (ErrorRecovery || IgnoreErr);
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);
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)) {
473 /* -----------------------------------------------------------------------------*/
477 * This function changes memory Pstate context
479 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
480 * @param[in] MemPstate - Target Memory Pstate
483 * ----------------------------------------------------------------------------
486 MemNChangeMemPStateContextNb (
487 IN OUT MEM_NB_BLOCK *NBPtr,
488 IN MEM_PSTATE MemPstate
491 UINT8 PSMasterChannel;
494 ASSERT ((MemPstate == 0) || (MemPstate == 1));
495 ASSERT (NBPtr->MemPstate == ((MemNGetBitFieldNb (NBPtr, BFMemPsSel) == 0) ? MEMORY_PSTATE0 : MEMORY_PSTATE1));
497 IDS_HDT_CONSOLE (MEM_FLOW, "\nGo to Memory Pstate Conext %d\n", MemPstate);
499 MemNSwitchDCTNb (NBPtr, 0);
500 // Figure out what is the master channel
501 PSMasterChannel = (UINT8) (MemNGetBitFieldNb (NBPtr, BFPhyPSMasterChannel) >> 8);
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);
509 NBPtr->MemPstate = (MemPstate == 0) ? MEMORY_PSTATE0 : MEMORY_PSTATE1;
510 MemNSwitchDCTNb (NBPtr, Dct);
513 /* -----------------------------------------------------------------------------*/
516 * This function allocates buffer for NB register table
518 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
519 * @param[in] Handle - Handle for heap allocation for NBRegTable
521 * @return TRUE - Successfully allocates buffer the first time
522 * @return FALSE - Buffer already allocated or fails to allocate
526 MemNAllocateNBRegTableNb (
527 IN OUT MEM_NB_BLOCK *NBPtr,
528 IN NB_REG_TAB_HANDLE Handle
531 ALLOCATE_HEAP_PARAMS AllocHeapParams;
532 LOCATE_HEAP_PTR LocHeap;
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;
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
549 NBPtr->NBRegTable = (TSEFO *)AllocHeapParams.BufferPtr;