| /** |
| * @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); |
| } |
| } |
| } |
| } |
| } |
| |