blob: d275f060ee916b8f430116c18ac8dc07d16d82d8 [file] [log] [blame]
/**
* @file
*
* System Tuning Family 10h specific routines
*
* Support for Traffic Distribution and buffer tunings which
* can not be done in a register table.
*
* @xrefitem bom "File Content Label" "Release Content"
* @e project: AGESA
* @e sub-project: HyperTransport
* @e \$Revision: 44323 $ @e \$Date: 2010-12-22 01:24:58 -0700 (Wed, 22 Dec 2010) $
*
*/
/*
*****************************************************************************
*
* Copyright (c) 2011, 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 "amdlib.h"
#include "Ids.h"
#include "Topology.h"
#include "htFeat.h"
#include "htInterface.h"
#include "htNb.h"
#include "htNbHardwareFam10.h"
#include "htNbSystemFam10.h"
#include "Filecode.h"
#define FILECODE PROC_HT_FAM10_HTNBSYSTEMFAM10_FILECODE
/*----------------------------------------------------------------------------
* DEFINITIONS AND MACROS
*
*----------------------------------------------------------------------------
*/
/*----------------------------------------------------------------------------
* TYPEDEFS AND STRUCTURES
*
*----------------------------------------------------------------------------
*/
/**
* Register Fields for an individual link pair.
*/
typedef struct {
UINT32 Enable:1; ///< Enable distribution on this pair.
UINT32 Asymmetric:1; ///< Links are different widths.
UINT32 MasterSelect:3; ///< The master link.
UINT32 AlternateSelect:3; ///< The alternate link.
} PAIR_SELECT_FIELDS;
/**
* Register access union for ::PAIR_SELECT_FIELDS.
*/
typedef union {
UINT32 Value; ///< access as a 32 bit value or register.
PAIR_SELECT_FIELDS Fields; ///< access individual fields.
} PAIR_SELECT;
/*----------------------------------------------------------------------------
* PROTOTYPES OF LOCAL FUNCTIONS
*
*----------------------------------------------------------------------------
*/
/***************************************************************************
*** FAMILY/NORTHBRIDGE SPECIFIC FUNCTIONS ***
***************************************************************************/
/*----------------------------------------------------------------------------------------*/
/**
* Set the traffic distribution register for the Links provided.
*
* @HtNbMethod{::F_WRITE_TRAFFIC_DISTRIBUTION}
*
* @param[in] Links01 coherent Links from Node 0 to 1
* @param[in] Links10 coherent Links from Node 1 to 0
* @param[in] Nb this northbridge
*/
VOID
Fam10WriteTrafficDistribution (
IN UINT32 Links01,
IN UINT32 Links10,
IN NORTHBRIDGE *Nb
)
{
UINT32 Temp;
PCI_ADDR TrafficDistReg;
TrafficDistReg.AddressValue = MAKE_SBDFO (MakePciSegmentFromNode (0),
MakePciBusFromNode (0),
MakePciDeviceFromNode (0),
CPU_HTNB_FUNC_00,
REG_HT_TRAFFIC_DIST_0X164);
// Node 0
// DstLnk
LibAmdPciWriteBits (TrafficDistReg, 23, 16, &Links01, Nb->ConfigHandle);
// DstNode = 1, cHTPrbDistEn = 1, cHTRspDistEn = 1, cHTReqDistEn = 1
Temp = 0x0107;
LibAmdPciWriteBits (TrafficDistReg, 15, 0, &Temp, Nb->ConfigHandle);
TrafficDistReg.AddressValue = MAKE_SBDFO (MakePciSegmentFromNode (1),
MakePciBusFromNode (1),
MakePciDeviceFromNode (1),
CPU_HTNB_FUNC_00,
REG_HT_TRAFFIC_DIST_0X164);
// Node 1
// DstLnk
LibAmdPciWriteBits (TrafficDistReg, 23, 16, &Links10, Nb->ConfigHandle);
// DstNode = 0, cHTPrbDistEn = 1, cHTRspDistEn = 1, cHTReqDistEn = 1
Temp = 0x0007;
LibAmdPciWriteBits (TrafficDistReg, 15, 0, &Temp, Nb->ConfigHandle);
}
/*----------------------------------------------------------------------------------------*/
/**
* Write a link pair to the link pair distribution and fixups.
*
* @HtNbMethod{::F_WRITE_LINK_PAIR_DISTRIBUTION}
*
* Set the links as a pair using the link pair index provided. Set asymmetric attribute as
* provided. If the Master Link is not currently used as the route, fixup the routes for all
* nodes which specify the alternate link.
*
* @param[in] Node Set the pair on this node
* @param[in] ConnectedNode The Node to which this link pair directly connects.
* @param[in] Pair Using this pair set in the register
* @param[in] Asymmetric True if different widths
* @param[in] MasterLink Set this as the master link and in the route
* @param[in] AlternateLink Set this as the alternate link
* @param[in] Nb this northbridge
*
*/
VOID
Fam10WriteLinkPairDistribution (
IN UINT8 Node,
IN UINT8 ConnectedNode,
IN UINT8 Pair,
IN BOOLEAN Asymmetric,
IN UINT8 MasterLink,
IN UINT8 AlternateLink,
IN NORTHBRIDGE *Nb
)
{
PCI_ADDR Reg;
UINT32 CurrentRoute;
UINT32 MasterRoute;
UINT32 AlternateRoute;
PAIR_SELECT Selection;
UINT32 RouteIndex;
ASSERT ((Node < MAX_NODES) && (ConnectedNode < MAX_NODES));
ASSERT (Pair < MAX_LINK_PAIRS);
ASSERT (MasterLink < Nb->MaxLinks);
ASSERT (AlternateLink < Nb->MaxLinks);
// Make the master link the route for all routes to or through NodeB, by replacing all occurrences of
// Alternate link with Master link. If routing used the master link, no update is necessary.
MasterRoute = (((1 << Nb->BroadcastSelfBit) | Nb->SelfRouteResponseMask | Nb->SelfRouteRequestMask) << (MasterLink + 1));
AlternateRoute = (((1 << Nb->BroadcastSelfBit) | Nb->SelfRouteResponseMask | Nb->SelfRouteRequestMask) << (AlternateLink + 1));
Reg.AddressValue = MAKE_SBDFO (MakePciSegmentFromNode (Node),
MakePciBusFromNode (Node),
MakePciDeviceFromNode (Node),
CPU_HTNB_FUNC_00,
REG_ROUTE0_0X40);
for (RouteIndex = 0; RouteIndex < MAX_NODES; RouteIndex++) {
Reg.Address.Register = REG_ROUTE0_0X40 + (RouteIndex * 4);
LibAmdPciReadBits (Reg, 31, 0, &CurrentRoute, Nb->ConfigHandle);
if ((CurrentRoute & AlternateRoute) != 0) {
// Since Master and Alternate are redundant, the route must use one or the other but not both.
ASSERT ((CurrentRoute & MasterRoute) == 0);
// Set the master route for Request, Response or Broadcast only if the alternate was used for that case.
// Example, use of a link as a broadcast link is typically not the same route register as its use for Request, Response.
CurrentRoute = ((CurrentRoute & ~AlternateRoute) |
((((CurrentRoute & AlternateRoute) >> (AlternateLink + 1)) << (MasterLink + 1)) & MasterRoute));
LibAmdPciWriteBits (Reg, 31, 0, &CurrentRoute, Nb->ConfigHandle);
}
}
// Set the Link Pair and Enable it
Selection.Fields.Enable = 1;
Selection.Fields.Asymmetric = Asymmetric;
Selection.Fields.MasterSelect = MasterLink;
Selection.Fields.AlternateSelect = AlternateLink;
Reg.AddressValue = MAKE_SBDFO (MakePciSegmentFromNode (Node),
MakePciBusFromNode (Node),
MakePciDeviceFromNode (Node),
CPU_HTNB_FUNC_00,
REG_HT_LINK_PAIR_DIST_0X1E0);
LibAmdPciWriteBits (
Reg,
((PAIR_SELECT_OFFSET * (Pair + 1)) - 1),
(PAIR_SELECT_OFFSET * Pair),
&Selection.Value,
Nb->ConfigHandle
);
}
/*----------------------------------------------------------------------------------------*/
/**
* Family 10h specific tunings.
*
* @HtNbMethod{::F_BUFFER_OPTIMIZATIONS}
*
* Buffer tunings are inherently northbridge specific. Check for specific configs
* which require adjustments and apply any standard workarounds to this Node.
*
* @param[in] Node the Node to tune
* @param[in] State global state
* @param[in] Nb this northbridge
*/
VOID
Fam10BufferOptimizations (
IN UINT8 Node,
IN STATE_DATA *State,
IN NORTHBRIDGE *Nb
)
{
UINT32 Temp;
PCI_ADDR currentPtr;
PCI_ADDR GangedReg;
UINT8 i;
ASSERT (Node < MAX_NODES);
//
// Link to XCS Token Count Tuning
//
// For each active Link that we reganged (so this unfortunately can't go into the PCI reg
// table), we have to switch the Link to XCS Token Counts to the ganged state.
// We do this here for the non - uma case, which is to write the values that would have
// been power on defaults if the Link was ganged at cold reset.
//
for (i = 0; i < (State->TotalLinks * 2); i++) {
if (((*State->PortList)[i].NodeID == Node) && ((*State->PortList)[i].Type == PORTLIST_TYPE_CPU)) {
// If the Link is greater than 4, this is a subLink 1, so it is not reganged.
if ((*State->PortList)[i].Link < 4) {
currentPtr.AddressValue = MAKE_SBDFO (MakePciSegmentFromNode (Node),
MakePciBusFromNode (Node),
MakePciDeviceFromNode (Node),
CPU_NB_FUNC_03,
REG_NB_LINK_XCS_TOKEN0_3X148 + (4 * (*State->PortList)[i].Link)
);
if ((*State->PortList)[i].SelRegang) {
// Handle all the regang Token count adjustments
// SubLink 0: [Probe0tok] = 2 [Rsp0tok] = 2 [PReq0tok] = 2 [Req0tok] = 2
Temp = 0xAA;
LibAmdPciWriteBits (currentPtr, 7, 0, &Temp, Nb->ConfigHandle);
// SubLink 1: [Probe1tok] = 0 [Rsp1tok] = 0 [PReq1tok] = 0 [Req1tok] = 0
Temp = 0;
LibAmdPciWriteBits (currentPtr, 23, 16, &Temp, Nb->ConfigHandle);
// [FreeTok] = 3
Temp = 3;
LibAmdPciWriteBits (currentPtr, 15, 14, &Temp, Nb->ConfigHandle);
} else {
// Read the regang bit in hardware
GangedReg.AddressValue = MAKE_SBDFO (MakePciSegmentFromNode ((*State->PortList)[i].NodeID),
MakePciBusFromNode ((*State->PortList)[i].NodeID),
MakePciDeviceFromNode ((*State->PortList)[i].NodeID),
CPU_HTNB_FUNC_00,
REG_HT_LINK_EXT_CONTROL0_0X170 + (4 * (*State->PortList)[i].Link));
LibAmdPciReadBits (GangedReg, 0, 0, &Temp, Nb->ConfigHandle);
if (Temp == 1) {
// handle a minor adjustment for strapped ganged Links. If SelRegang is false we
// didn't do the regang, so if the bit is on then it's hardware strapped.
//
// [FreeTok] = 3
Temp = 3;
LibAmdPciWriteBits (currentPtr, 15, 14, &Temp, Nb->ConfigHandle);
}
}
}
}
}
}
/*----------------------------------------------------------------------------------------*/
/**
* Family 10h specific tunings.
*
* @HtNbMethod{::F_BUFFER_OPTIMIZATIONS}
*
* Buffer tunings are inherently northbridge specific. Check for specific configs
* which require adjustments and apply any standard workarounds to this Node.
*
* @param[in] Node the Node to tune
* @param[in] State global state
* @param[in] Nb this northbridge
*/
VOID
Fam10RevDBufferOptimizations (
IN UINT8 Node,
IN STATE_DATA *State,
IN NORTHBRIDGE *Nb
)
{
UINT32 Temp;
PCI_ADDR Reg;
UINT8 i;
FINAL_LINK_STATE FinalLinkState;
UINT32 Widthin;
UINT32 Widthout;
ASSERT (Node < MAX_NODES);
//
// Internal link fixup.
// When powering off internal link 2, a performance optimization may be possible where its buffers
// can be made available to the external paired sublink. If the conditions are met, do the fix up here.
//
for (i = 0; i < (State->TotalLinks * 2); i++) {
if (((*State->PortList)[i].NodeID == Node) && ((*State->PortList)[i].Type == PORTLIST_TYPE_CPU)) {
// Is this a sublink 0 paired with internal link 2?
if (((*State->PortList)[i].Link < 4) &&
(Nb->GetPackageLink (Node, ((*State->PortList)[i].Link + 4), Nb) == HT_LIST_MATCH_INTERNAL_LINK_2)) {
FinalLinkState = State->HtInterface->GetIgnoreLink (Node, ((*State->PortList)[i].Link + 4), Nb->DefaultIgnoreLinkList, State);
// Are we ignoring the internal link 2 with Power Off?
if (FinalLinkState == POWERED_OFF) {
// Read the regang bit in hardware.
Reg.AddressValue = MAKE_SBDFO (MakePciSegmentFromNode (Node),
MakePciBusFromNode (Node),
MakePciDeviceFromNode (Node),
CPU_HTNB_FUNC_00,
REG_HT_LINK_EXT_CONTROL0_0X170 + (4 * (*State->PortList)[i].Link));
LibAmdPciReadBits (Reg, 0, 0, &Temp, Nb->ConfigHandle);
// If it's already ganged, skip to the width fix up.
if (Temp == 0) {
// Clear EndOfChain / XmitOff on internal sublink
Reg = Nb->MakeLinkBase (Node, ((*State->PortList)[i].Link + 4), Nb);
Reg.Address.Register += HTHOST_LINK_CONTROL_REG;
Temp = 0;
State->HtFeatures->SetHtControlRegisterBits (Reg, 7, 6, &Temp, State);
// Gang the link
Nb->SetLinkRegang (Node, (*State->PortList)[i].Link, Nb);
}
// Set InLnSt = PHY_OFF in register table.
// Set sublink 0 widths to 8 bits
if ((*State->PortList)[i].SelWidthOut > 8) {
(*State->PortList)[i].SelWidthOut = 8;
}
if ((*State->PortList)[i].SelWidthIn > 8) {
(*State->PortList)[i].SelWidthIn = 8;
}
Widthout = State->HtFeatures->ConvertWidthToBits ((*State->PortList)[i].SelWidthOut);
Widthin = State->HtFeatures->ConvertWidthToBits ((*State->PortList)[i].SelWidthIn);
Temp = (Widthin & 7) | ((Widthout & 7) << 4);
Reg = Nb->MakeLinkBase (Node, (*State->PortList)[i].Link, Nb);
Reg.Address.Register += HTHOST_LINK_CONTROL_REG;
State->HtFeatures->SetHtControlRegisterBits (Reg, 31, 24, &Temp, State);
}
}
}
}
}