/* $NoKeywords:$ */
/**
 * @file
 *
 * mn.c
 *
 * Common Northbridge functions
 *
 * @xrefitem bom "File Content Label" "Release Content"
 * @e project: AGESA
 * @e sub-project: (Mem/NB/)
 * @e \$Revision: 56279 $ @e \$Date: 2011-07-11 13:11:28 -0600 (Mon, 11 Jul 2011) $
 *
 **/
/*****************************************************************************
*
* Copyright (C) 2012 Advanced Micro Devices, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in the
*       documentation and/or other materials provided with the distribution.
*     * Neither the name of Advanced Micro Devices, Inc. nor the names of
*       its contributors may be used to endorse or promote products derived
*       from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* ***************************************************************************
*
*/
/*
 *----------------------------------------------------------------------------
 *                                MODULES USED
 *
 *----------------------------------------------------------------------------
 */

#include "AGESA.h"
#include "AdvancedApi.h"
#include "amdlib.h"
#include "Ids.h"
#include "mport.h"
#include "OptionMemory.h"
#include "mm.h"
#include "mn.h"
#include "mu.h"
#include "Filecode.h"
CODE_GROUP (G1_PEICC)
RDATA_GROUP (G2_PEI)

#define FILECODE PROC_MEM_NB_MN_FILECODE


/*----------------------------------------------------------------------------
 *                          DEFINITIONS AND MACROS
 *
 *----------------------------------------------------------------------------
 */
/*----------------------------------------------------------------------------
 *                           TYPEDEFS AND STRUCTURES
 *
 *----------------------------------------------------------------------------
 */

/*----------------------------------------------------------------------------
 *                        PROTOTYPES OF LOCAL FUNCTIONS
 *
 *----------------------------------------------------------------------------
 */
BOOLEAN
STATIC
MemNDefaultFamilyHookNb (
  IN OUT   MEM_NB_BLOCK *NBPtr,
  IN OUT   VOID *OptParam
  );

/*----------------------------------------------------------------------------
 *                            EXPORTED FUNCTIONS
 *
 *----------------------------------------------------------------------------
 */
extern OPTION_MEM_FEATURE_NB* memNTrainFlowControl[];

extern BUILD_OPT_CFG UserOptions;

/* -----------------------------------------------------------------------------*/
/**
 *
 *   This function initializes member functions and variables of NB block.
 *
 *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
 *
 */

VOID
MemNInitNBDataNb (
  IN OUT   MEM_NB_BLOCK *NBPtr
  )
{
  INT32 i;
  UINT8 *BytePtr;

  NBPtr->DctCachePtr = NBPtr->DctCache;
  NBPtr->PsPtr = NBPtr->PSBlock;

  BytePtr = (UINT8 *) (NBPtr->DctCache);
  for (i = 0; i < sizeof (NBPtr->DctCache); i++) {
    *BytePtr++ = 0;
  }

  for (i = 0; i < EnumSize; i++) {
    NBPtr->IsSupported[i] = FALSE;
  }

  for (i = 0; i < NumberOfHooks; i++) {
    NBPtr->FamilySpecificHook[i] = MemNDefaultFamilyHookNb;
  }

  for (i = 0; i < NBPtr->DctCount; i++) {
    NBPtr->PSBlock[i].MemPGetPass1Seeds = (BOOLEAN (*) (MEM_NB_BLOCK *)) memDefTrue;
  }

  NBPtr->SwitchDCT = MemNSwitchDCTNb;
  NBPtr->SwitchChannel = MemNSwitchChannelNb;
  NBPtr->GetBitField = MemNGetBitFieldNb;
  NBPtr->SetBitField = MemNSetBitFieldNb;
}

/* -----------------------------------------------------------------------------*/
/**
 *
 *
 *   Get System address of Chipselect RJ 16 bits (Addr[47:16])
 *
 *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
 *     @param[in]       Receiver - Chipselect to be targeted [0-7]
 *     @param[out]      AddrPtr -  Pointer to System Address [47:16]
 *
 *     @return      TRUE  - Address is valid
 *     @return      FALSE  - Address is not valid
 */

BOOLEAN
MemNGetMCTSysAddrNb (
  IN OUT   MEM_NB_BLOCK *NBPtr,
  IN       UINT8 Receiver,
     OUT   UINT32 *AddrPtr
  )
{
  S_UINT64 SMsr;
  UINT32 CSBase;
  UINT32 HoleBase;
  UINT32 DctSelBaseAddr;
  UINT32 BottomUma;
  DIE_STRUCT *MCTPtr;
  MEM_DATA_STRUCT *MemPtr;

  MCTPtr = NBPtr->MCTPtr;
  MemPtr = NBPtr->MemPtr;

  ASSERT (Receiver < 8);

  CSBase = MemNGetBitFieldNb (NBPtr, BFCSBaseAddr0Reg + Receiver);
  if (CSBase & 1) {
    ASSERT ((CSBase & 0xE0) == 0);   // Should not enable CS interleaving before DQS training.

    // Scale base address from [39:8] to [47:16]
    CSBase >>= 8;

    HoleBase = MCTPtr->NodeHoleBase ? MCTPtr->NodeHoleBase : 0x7FFFFFFF;

    if ((MemNGetBitFieldNb (NBPtr, BFDctSelHiRngEn) == 1) && (NBPtr->Dct == MemNGetBitFieldNb (NBPtr, BFDctSelHi))) {
      DctSelBaseAddr = MemNGetBitFieldNb (NBPtr, BFDctSelBaseAddr) << (27 - 16);
      if (DctSelBaseAddr > HoleBase) {
        DctSelBaseAddr -= _4GB_RJ16 - HoleBase;
      }
      CSBase += DctSelBaseAddr;
    } else {
      CSBase += MCTPtr->NodeSysBase;
    }

    if (CSBase >= HoleBase) {
      CSBase += _4GB_RJ16 - HoleBase;
    }

    CSBase += (UINT32)1 << (21 - 16);  // Add 2MB offset to avoid compat area.
    if ((CSBase >= (MCT_TRNG_KEEPOUT_START >> 8)) && (CSBase <= (MCT_TRNG_KEEPOUT_END >> 8))) {
      CSBase += (((MCT_TRNG_KEEPOUT_END >> 8) - CSBase) + 0x0F) & 0xFFFFFFF0;
    }

    if (MCTPtr->Status[SbHWHole]) {
      if (MCTPtr->Status[SbSWNodeHole]) {
        LibAmdMsrRead (TOP_MEM, (UINT64 *)&SMsr, &MemPtr->StdHeader);

        if ((CSBase >= (SMsr.lo >> 16)) && (CSBase < _4GB_RJ16)) {
          return FALSE;
        }
      }
    }

    BottomUma = NBPtr->RefPtr->Sub4GCacheTop >> 16;
    if (BottomUma && (CSBase >= BottomUma) && (CSBase < _4GB_RJ16)) {
      return FALSE;
    }
    *AddrPtr = CSBase;
    return TRUE;
  }
  return FALSE;
}

/* -----------------------------------------------------------------------------*/
/**
 *
 *   This function determines if a Rank is enabled.
 *
 *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
 *     @param[in]    Receiver - Receiver to check
 *     @return - FALSE
 *
 */

BOOLEAN
MemNRankEnabledNb (
  IN OUT   MEM_NB_BLOCK *NBPtr,
  IN       UINT8 Receiver
  )
{
  UINT32 CSBase;
  CSBase = MemNGetBitFieldNb (NBPtr, BFCSBaseAddr0Reg + Receiver);
  if (CSBase & 1) {
    return  TRUE;
  } else {
    return  FALSE;
  }
}

/* -----------------------------------------------------------------------------*/
/**
 *
 *
 *     This function sets the EccSymbolSize bit depending upon configurations
 *     and system override.
 *
 *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
 *
 */

VOID
MemNSetEccSymbolSizeNb (
  IN OUT   MEM_NB_BLOCK *NBPtr
  )
{
  UINT16 X4DimmsOnly;
  BOOLEAN Size;
  DIE_STRUCT *MCTPtr;
  DCT_STRUCT *DCTPtr;

  ASSERT (NBPtr != NULL);

  MCTPtr = NBPtr->MCTPtr;
  DCTPtr = NBPtr->DCTPtr;

  // Determine if this node has only x4 DRAM parts
  X4DimmsOnly = (UINT16) ((!(DCTPtr->Timings.Dimmx8Present | DCTPtr->Timings.Dimmx16Present)) && DCTPtr->Timings.Dimmx4Present);
  //
  // Check if EccSymbolSize BKDG value is overridden
  //
  if (UserOptions.CfgEccSymbolSize != ECCSYMBOLSIZE_USE_BKDG) {
    Size = (UserOptions.CfgEccSymbolSize == ECCSYMBOLSIZE_FORCE_X4) ? FALSE : TRUE;
  } else {
    if (X4DimmsOnly && MCTPtr->GangedMode) {
      Size = FALSE;
    } else {
      Size = TRUE;
    }
  }
  IDS_OPTION_HOOK (IDS_ECCSYMBOLSIZE, &Size, &(NBPtr->MemPtr->StdHeader));
  MemNSetBitFieldNb (NBPtr, BFEccSymbolSize, (UINT32) Size);
}

/* -----------------------------------------------------------------------------*/
/**
 *
 *      This function sets the training control flow
 *      The DDR3 mode bit must be set prior to calling this function
 *
 *      @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
 */
BOOLEAN
MemNTrainingFlowNb (
  IN OUT   MEM_NB_BLOCK *NBPtr
  )
{
  if (MemNGetBitFieldNb (NBPtr, BFDdr3Mode)!= 0) {
    memNTrainFlowControl[DDR3_TRAIN_FLOW] (NBPtr);
  } else {
    memNTrainFlowControl[DDR2_TRAIN_FLOW] (NBPtr);
  }
  return TRUE;
}

/*-----------------------------------------------------------------------------*/
/**
 *
 *      This function flushes the  training pattern
 *     @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
 *     @param[in] Address - System Address [47:16]
 *     @param[in] ClCount - Number of cache lines
 *
 */

VOID
MemNFlushPatternNb (
  IN OUT   MEM_NB_BLOCK *NBPtr,
  IN       UINT32 Address,
  IN       UINT16 ClCount
  )
{
  // Due to speculative execution during MemUReadCachelines, we must
  //  flush one more cache line than we read.
  MemUProcIOClFlush (Address, ClCount + 1, NBPtr->MemPtr);
}

/* -----------------------------------------------------------------------------*/
/**
 *
 *     This function compares test pattern with data in buffer and
 *     return a pass/fail bitmap for 8 bytelanes (upper 8 bits are reserved)
 *
 *     @param[in,out]   *NBPtr    - Pointer to the MEM_NB_BLOCK
 *     @param[in]       Buffer[]  - Buffer data from DRAM (Measured data from DRAM) to compare
 *     @param[in]       Pattern[] - Pattern (Expected data in ROM/CACHE) to compare against
 *     @param[in]       ByteCount - Byte count
 *
 *     @return  PASS - Bitmap of results of comparison
 */

UINT16
MemNCompareTestPatternNb (
  IN OUT   MEM_NB_BLOCK *NBPtr,
  IN       UINT8 Buffer[],
  IN       UINT8 Pattern[],
  IN       UINT16 ByteCount
  )
{
  UINT16 i;
  UINT16 Pass;
  UINT8 ColumnCount;
  UINT8 FailingBitMask[8];

  ASSERT ((ByteCount == 18 * 64) || (ByteCount == 9 * 64) || (ByteCount == 64 * 64) || (ByteCount == 32 * 64) || (ByteCount == 3 * 64));

  ColumnCount = NBPtr->ChannelPtr->ColumnCount;
  Pass = 0xFFFF;
  //
  // Clear Failing Bit Mask
  //
  for (i = 0; i < sizeof (FailingBitMask); i++) {
    FailingBitMask[i] = 0;
  }

  if (NBPtr->Ganged && (NBPtr->Dct != 0)) {
    i = 8;   // DCT 1 in ganged mode
  } else {
    i = 0;
  }

  for (; i < ByteCount; i++) {
    if (Buffer[i] != Pattern[i]) {
      // if bytelane n fails
      Pass &= ~((UINT16)1 << (i % 8));    // clear bit n
      FailingBitMask[i % NBPtr->TechPtr->MaxByteLanes ()] |= (Buffer[i] ^ Pattern[i]);
    }

    if (NBPtr->Ganged && ((i & 7) == 7)) {
      i += 8;     // if ganged, skip over other Channel's Data
    }
  }
  //
  // Accumulate Failing bit data
  //
  for (i = 0; i < sizeof (FailingBitMask); i++) {
    NBPtr->ChannelPtr->FailingBitMask[(ColumnCount * NBPtr->TechPtr->ChipSel) + i] &=
      FailingBitMask[i];
  }

  return Pass;
}

/*-----------------------------------------------------------------------------
 *
 *
 *     This function compares test pattern with data in buffer and
 *     return a pass/fail bitmap for 8 bytelanes (upper 8 bits are reserved)
 *
 *     @param[in,out]  *NBPtr     - Pointer to the MEM_NB_BLOCK
 *     @param[in]       Buffer[]  - Buffer data from DRAM (Measured data from DRAM) to compare
 *     @param[in]       Pattern[] - Pattern (Expected data in ROM/CACHE) to compare against
 *     @param[in]       ByteCount - Byte count
 *
 *     @retval  PASS - Bitmap of results of comparison
 * ----------------------------------------------------------------------------
 */
UINT16
MemNInsDlyCompareTestPatternNb (
  IN       MEM_NB_BLOCK *NBPtr,
  IN       UINT8 Buffer[],
  IN       UINT8 Pattern[],
  IN       UINT16 ByteCount
  )
{
  UINT16 i;
  UINT16 Pass;
  UINT16 BeatOffset;
  UINT16 BeatCnt;
  UINT8 ColumnCount;
  UINT8 FailingBitMask[8];

  ASSERT ((ByteCount == 18 * 64) || (ByteCount == 9 * 64) || (ByteCount == 64 * 64) || (ByteCount == 32 * 64) || (ByteCount == 3 * 64));

  ColumnCount = NBPtr->ChannelPtr->ColumnCount;
  Pass = 0xFFFF;
  //
  // Clear Failing Bit Mask
  //
  for (i = 0; i < sizeof (FailingBitMask); i++) {
    FailingBitMask[i] = 0;
  }

  if (NBPtr->Ganged && (NBPtr->Dct != 0)) {
    i = 8;   // DCT 1 in ganged mode
  } else {
    i = 0;
  }

  if (NBPtr->Ganged) {
    BeatOffset = 16;
  } else {
    BeatOffset = 8;
  }

  BeatCnt = 0;
  for (; i < ByteCount; i++) {

    if (Buffer[i] != Pattern[i + BeatOffset]) {
      // if bytelane n fails
      Pass &= ~((UINT16)1 << (i % 8));    // clear bit n
      FailingBitMask[i % NBPtr->TechPtr->MaxByteLanes ()] |= (Buffer[i] ^ Pattern[i + BeatOffset]);
    }

    if ((i & 7) == 7) {
      if (NBPtr->Ganged) {
        i += 8;     // if ganged, skip over other Channel's Data
      }
      BeatCnt++;
    }

    if ((BeatCnt & 3) == 3) {
      // Skip last data beat of a 4-beat burst.
      BeatCnt++;
      i = i + BeatOffset;
    }
  }
  //
  // Accumulate Failing bit data
  //
  for (i = 0; i < sizeof (FailingBitMask); i++) {
    NBPtr->ChannelPtr->FailingBitMask[(ColumnCount * NBPtr->TechPtr->ChipSel) + i] &=
      FailingBitMask[i];
  }

  return Pass;
}

/* -----------------------------------------------------------------------------*/
/**
 *
 *      This function sets the training control flow for UNB
 *      The DDR3 mode bit must be set prior to calling this function
 *
 *      @param[in,out]   *NBPtr   - Pointer to the MEM_NB_BLOCK
 */
BOOLEAN
MemNTrainingFlowUnb (
  IN OUT   MEM_NB_BLOCK *NBPtr
  )
{
  memNTrainFlowControl[DDR3_TRAIN_FLOW] (NBPtr);
  return TRUE;
}
/*----------------------------------------------------------------------------
 *                              LOCAL FUNCTIONS
 *
 *----------------------------------------------------------------------------
 */

/*-----------------------------------------------------------------------------
 *
 *
 *     This function is an empty function used to intialize FamilySpecificHook array
 *
 *     @param[in,out]  *NBPtr     - Pointer to the MEM_NB_BLOCK
 *     @param[in,out]  OptParam   - Optional parameter
 *
 *     @return  TRUE - always
 * ----------------------------------------------------------------------------
 */
BOOLEAN
STATIC
MemNDefaultFamilyHookNb (
  IN OUT   MEM_NB_BLOCK *NBPtr,
  IN OUT   VOID *OptParam
  )
{
  return TRUE;
}
