AGESA F15: AMD family15 AGESA code
[coreboot.git] / src / vendorcode / amd / agesa / f15 / Proc / HT / Fam15 / htNbSystemFam15.c
1 /* $NoKeywords:$ */
2 /**
3  * @file
4  *
5  * System Tuning Family 15h specific routines
6  *
7  * Support for Traffic Distribution and buffer tunings which
8  * can not be done in a register table.
9  *
10  * @xrefitem bom "File Content Label" "Release Content"
11  * @e project:      AGESA
12  * @e sub-project:  HyperTransport
13  * @e \$Revision: 50215 $   @e \$Date: 2011-04-05 20:50:13 -0600 (Tue, 05 Apr 2011) $
14  *
15  */
16 /*
17 *****************************************************************************
18 *
19 * Copyright (C) 2012 Advanced Micro Devices, Inc.
20 * All rights reserved.
21 *
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions are met:
24 *     * Redistributions of source code must retain the above copyright
25 *       notice, this list of conditions and the following disclaimer.
26 *     * Redistributions in binary form must reproduce the above copyright
27 *       notice, this list of conditions and the following disclaimer in the
28 *       documentation and/or other materials provided with the distribution.
29 *     * Neither the name of Advanced Micro Devices, Inc. nor the names of
30 *       its contributors may be used to endorse or promote products derived
31 *       from this software without specific prior written permission.
32 *
33 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
34 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
35 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
37 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
39 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
40 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
41 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
42 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43 *
44 * ***************************************************************************
45 *
46 */
47
48 /*
49  *----------------------------------------------------------------------------
50  *                                MODULES USED
51  *
52  *----------------------------------------------------------------------------
53  */
54
55
56
57 #include "AGESA.h"
58 #include "amdlib.h"
59 #include "Ids.h"
60 #include "Topology.h"
61 #include "htFeat.h"
62 #include "htInterface.h"
63 #include "htNb.h"
64 #include "htNbCommonHardware.h"
65 #include "htNbSystemFam15.h"
66 #include "Filecode.h"
67 CODE_GROUP (G2_PEI)
68 RDATA_GROUP (G2_PEI)
69 #define FILECODE PROC_HT_FAM15_HTNBSYSTEMFAM15_FILECODE
70 /*----------------------------------------------------------------------------
71  *                          DEFINITIONS AND MACROS
72  *
73  *----------------------------------------------------------------------------
74  */
75
76 /*----------------------------------------------------------------------------
77  *                           TYPEDEFS AND STRUCTURES
78  *
79  *----------------------------------------------------------------------------
80  */
81 /**
82  * Register Fields for an individual link pair.
83  */
84 typedef struct {
85   UINT32 Enable:1;            ///< Enable distribution on this pair.
86   UINT32 Asymmetric:1;        ///< Links are different widths.
87   UINT32 MasterSelect:3;      ///< The master link.
88   UINT32 AlternateSelect:3;   ///< The alternate link.
89 } PAIR_SELECT_FIELDS;
90
91 /**
92  * Register access union for ::PAIR_SELECT_FIELDS.
93  */
94 typedef union {
95   UINT32 Value;               ///< access as a 32 bit value or register.
96   PAIR_SELECT_FIELDS Fields;  ///< access individual fields.
97 } PAIR_SELECT;
98
99 /*----------------------------------------------------------------------------
100  *                        PROTOTYPES OF LOCAL FUNCTIONS
101  *
102  *----------------------------------------------------------------------------
103  */
104
105 /***************************************************************************
106  ***               FAMILY/NORTHBRIDGE SPECIFIC FUNCTIONS                 ***
107  ***************************************************************************/
108
109 /*----------------------------------------------------------------------------------------*/
110 /**
111  * Set the traffic distribution register for the Links provided.
112  *
113  * @HtNbMethod{::F_WRITE_TRAFFIC_DISTRIBUTION}
114  *
115  * @param[in]     Links01   coherent Links from Node 0 to 1
116  * @param[in]     Links10   coherent Links from Node 1 to 0
117  * @param[in]     Nb        this northbridge
118  */
119 VOID
120 Fam15WriteTrafficDistribution (
121   IN       UINT32       Links01,
122   IN       UINT32       Links10,
123   IN       NORTHBRIDGE  *Nb
124   )
125 {
126   UINT32 Temp;
127   PCI_ADDR TrafficDistReg;
128
129   TrafficDistReg.AddressValue = MAKE_SBDFO (MakePciSegmentFromNode (0),
130                                             MakePciBusFromNode (0),
131                                             MakePciDeviceFromNode (0),
132                                             CPU_HTNB_FUNC_00,
133                                             REG_HT_TRAFFIC_DIST_0X164);
134
135   // Node 0
136   // DstLnk
137   LibAmdPciWriteBits (TrafficDistReg, 23, 16, &Links01, Nb->ConfigHandle);
138   // DstNode = 1, cHTPrbDistEn = 1, cHTRspDistEn = 1, cHTReqDistEn = 1
139   Temp = 0x0107;
140   LibAmdPciWriteBits (TrafficDistReg, 15, 0, &Temp, Nb->ConfigHandle);
141
142   TrafficDistReg.AddressValue = MAKE_SBDFO (MakePciSegmentFromNode (1),
143                                             MakePciBusFromNode (1),
144                                             MakePciDeviceFromNode (1),
145                                             CPU_HTNB_FUNC_00,
146                                             REG_HT_TRAFFIC_DIST_0X164);
147
148   // Node 1
149   // DstLnk
150   LibAmdPciWriteBits (TrafficDistReg, 23, 16, &Links10, Nb->ConfigHandle);
151   // DstNode = 0, cHTPrbDistEn = 1, cHTRspDistEn = 1, cHTReqDistEn = 1
152   Temp = 0x0007;
153   LibAmdPciWriteBits (TrafficDistReg, 15, 0, &Temp, Nb->ConfigHandle);
154 }
155
156 /*----------------------------------------------------------------------------------------*/
157 /**
158  * Set the victim distribution register for the Links provided.
159  *
160  * @HtNbMethod{::F_WRITE_VICTIM_DISTRIBUTION}
161  *
162  * @param[in]     NodeA     Source Node from Node A To Node B and DstNode from Node A To Node B
163  * @param[in]     NodeB     Source Node from Node B To Node A and DstNode from Node A To Node B
164  * @param[in]     LinksAB   Victimed Link from Node A To Node B
165  * @param[in]     LinksBA   Victimed Link from Node B To Node A
166  * @param[in]     Nb        this northbridge
167  */
168 VOID
169 Fam15WriteVictimDistribution (
170   IN       UINT8        NodeA,
171   IN       UINT8        NodeB,
172   IN       UINT32       LinksAB,
173   IN       UINT32       LinksBA,
174   IN       NORTHBRIDGE  *Nb
175   )
176 {
177   UINT32 Temp;
178   PCI_ADDR TrafficDistReg;
179
180   TrafficDistReg.AddressValue = MAKE_SBDFO (MakePciSegmentFromNode (NodeA),
181                                             MakePciBusFromNode (NodeA),
182                                             MakePciDeviceFromNode (NodeA),
183                                             CPU_HTNB_FUNC_00,
184                                             REG_HT_TRAFFIC_DIST_0X164);
185
186   // Node A
187   // DstLnk
188   LibAmdPciWriteBits (TrafficDistReg, 23, 16, &LinksAB, Nb->ConfigHandle);
189   // DstNode = Node B, cHTPrbDistEn = 0, cHTRspDistEn = 1, cHTReqDistEn = 1, cHTVicDistMode = 1
190   Temp = NodeB;
191   Temp = (Temp << 8) | 0x0B;
192   LibAmdPciWriteBits (TrafficDistReg, 15, 0, &Temp, Nb->ConfigHandle);
193
194   TrafficDistReg.AddressValue = MAKE_SBDFO (MakePciSegmentFromNode (NodeB),
195                                             MakePciBusFromNode (NodeB),
196                                             MakePciDeviceFromNode (NodeB),
197                                             CPU_HTNB_FUNC_00,
198                                             REG_HT_TRAFFIC_DIST_0X164);
199
200   // Node B
201   // DstLnk
202   LibAmdPciWriteBits (TrafficDistReg, 23, 16, &LinksBA, Nb->ConfigHandle);
203   // DstNode = Node A, cHTPrbDistEn = 0, cHTRspDistEn = 1, cHTReqDistEn = 1, cHTVicDistMode = 1
204   Temp = NodeA;
205   Temp = (Temp << 8) | 0x0B;
206   LibAmdPciWriteBits (TrafficDistReg, 15, 0, &Temp, Nb->ConfigHandle);
207 }
208
209 /*----------------------------------------------------------------------------------------*/
210 /**
211  * Write a link pair to the link pair distribution and fixups.
212  *
213  * @HtNbMethod{::F_WRITE_LINK_PAIR_DISTRIBUTION}
214  *
215  * Set the links as a pair using the link pair index provided.  Set asymmetric attribute as
216  * provided. If the Master Link is not currently used as the route, fixup the routes for all
217  * nodes which specify the alternate link.
218  *
219  * @param[in]    Node           Set the pair on this node
220  * @param[in]    ConnectedNode  The Node to which this link pair directly connects.
221  * @param[in]    Pair           Using this pair set in the register
222  * @param[in]    Asymmetric     True if different widths
223  * @param[in]    MasterLink     Set this as the master link and in the route
224  * @param[in]    AlternateLink  Set this as the alternate link
225  * @param[in]    Nb             this northbridge
226  *
227  */
228 VOID
229 Fam15WriteLinkPairDistribution (
230   IN       UINT8        Node,
231   IN       UINT8        ConnectedNode,
232   IN       UINT8        Pair,
233   IN       BOOLEAN      Asymmetric,
234   IN       UINT8        MasterLink,
235   IN       UINT8        AlternateLink,
236   IN       NORTHBRIDGE  *Nb
237   )
238 {
239   PCI_ADDR Reg;
240   UINT32 CurrentRoute;
241   UINT32 MasterRoute;
242   UINT32 AlternateRoute;
243   PAIR_SELECT Selection;
244   UINT32 RouteIndex;
245
246   ASSERT ((Node < MAX_NODES) && (ConnectedNode < MAX_NODES));
247   ASSERT (Pair < MAX_LINK_PAIRS);
248   ASSERT (MasterLink < Nb->MaxLinks);
249   ASSERT (AlternateLink < Nb->MaxLinks);
250
251   // Make the master link the route for all routes to or through NodeB, by replacing all occurrences of
252   // Alternate link with Master link.  If routing used the master link, no update is necessary.
253   MasterRoute = (((1 << Nb->BroadcastSelfBit) | Nb->SelfRouteResponseMask | Nb->SelfRouteRequestMask) << (MasterLink + 1));
254   AlternateRoute = (((1 << Nb->BroadcastSelfBit) | Nb->SelfRouteResponseMask | Nb->SelfRouteRequestMask) << (AlternateLink + 1));
255   Reg.AddressValue = MAKE_SBDFO (MakePciSegmentFromNode (Node),
256                                  MakePciBusFromNode (Node),
257                                  MakePciDeviceFromNode (Node),
258                                  CPU_HTNB_FUNC_00,
259                                  REG_ROUTE0_0X40);
260   for (RouteIndex = 0; RouteIndex < MAX_NODES; RouteIndex++) {
261     Reg.Address.Register = REG_ROUTE0_0X40 + (RouteIndex * 4);
262     LibAmdPciReadBits (Reg, 31, 0, &CurrentRoute, Nb->ConfigHandle);
263     if ((CurrentRoute & AlternateRoute) != 0) {
264       // Since Master and Alternate are redundant, the route must use one or the other but not both.
265       ASSERT ((CurrentRoute & MasterRoute) == 0);
266       // Set the master route for Request, Response or Broadcast only if the alternate was used for that case.
267       // Example, use of a link as a broadcast link is typically not the same route register as its use for Request, Response.
268       CurrentRoute = ((CurrentRoute & ~AlternateRoute) |
269                       ((((CurrentRoute & AlternateRoute) >> (AlternateLink + 1)) << (MasterLink + 1)) & MasterRoute));
270       LibAmdPciWriteBits (Reg, 31, 0, &CurrentRoute, Nb->ConfigHandle);
271     }
272   }
273
274   // Set the Link Pair and Enable it
275   Selection.Fields.Enable = 1;
276   Selection.Fields.Asymmetric = Asymmetric;
277   Selection.Fields.MasterSelect = MasterLink;
278   Selection.Fields.AlternateSelect = AlternateLink;
279   Reg.AddressValue = MAKE_SBDFO (MakePciSegmentFromNode (Node),
280                                  MakePciBusFromNode (Node),
281                                  MakePciDeviceFromNode (Node),
282                                  CPU_HTNB_FUNC_00,
283                                  REG_HT_LINK_PAIR_DIST_0X1E0);
284   LibAmdPciWriteBits (
285     Reg,
286     ((PAIR_SELECT_OFFSET * (Pair + 1)) - 1),
287     (PAIR_SELECT_OFFSET * Pair),
288     &Selection.Value,
289     Nb->ConfigHandle
290     );
291 }
292
293 /*----------------------------------------------------------------------------------------*/
294 /**
295  * Family 15h specific tunings.
296  *
297  * @HtNbMethod{::F_BUFFER_OPTIMIZATIONS}
298  *
299  * Buffer tunings are inherently northbridge specific. Check for specific configs
300  * which require adjustments and apply any standard workarounds to this Node.
301  *
302  * @param[in]     Node   the Node to tune
303  * @param[in]     State  global state
304  * @param[in]     Nb     this northbridge
305  */
306 VOID
307 Fam15BufferOptimizations (
308   IN       UINT8       Node,
309   IN       STATE_DATA  *State,
310   IN       NORTHBRIDGE *Nb
311   )
312 {
313   UINT32 Temp;
314   PCI_ADDR Reg;
315   UINT8 i;
316   FINAL_LINK_STATE FinalLinkState;
317   UINT32 WidthIn;
318   UINT32 WidthOut;
319
320   ASSERT (Node < MAX_NODES);
321
322   //
323   // Internal link fixup.
324   // When powering off internal link 2, a performance optimization may be possible where its buffers
325   // can be made available to the external paired sublink.  If the conditions are met, do the fix up here.
326   //
327   for (i = 0; i < (State->TotalLinks * 2); i++) {
328     if (((*State->PortList)[i].NodeID == Node) && ((*State->PortList)[i].Type == PORTLIST_TYPE_CPU)) {
329       // Is this a sublink 0 paired with internal link 2?
330       if (((*State->PortList)[i].Link < 4) &&
331           (Nb->GetPackageLink (Node, ((*State->PortList)[i].Link + 4), Nb) == HT_LIST_MATCH_INTERNAL_LINK_2)) {
332         FinalLinkState = State->HtInterface->GetIgnoreLink (Node, ((*State->PortList)[i].Link + 4), Nb->DefaultIgnoreLinkList, State);
333         // Are we ignoring the internal link 2 with Power Off?
334         if (FinalLinkState == POWERED_OFF) {
335           // Read the regang bit in hardware.
336           Reg.AddressValue = MAKE_SBDFO (MakePciSegmentFromNode (Node),
337                                          MakePciBusFromNode (Node),
338                                          MakePciDeviceFromNode (Node),
339                                          CPU_HTNB_FUNC_00,
340                                          REG_HT_LINK_EXT_CONTROL0_0X170 + (4 * (*State->PortList)[i].Link));
341           LibAmdPciReadBits (Reg, 0, 0, &Temp, Nb->ConfigHandle);
342           // If it's already ganged, skip to the width fix up.
343           if (Temp == 0) {
344             // Clear EndOfChain / XmitOff of internal sublink
345             Reg = Nb->MakeLinkBase (Node, ((*State->PortList)[i].Link + 4), Nb);
346             Reg.Address.Register += HTHOST_LINK_CONTROL_REG;
347             Temp = 0;
348             State->HtFeatures->SetHtControlRegisterBits (Reg, 7, 6, &Temp, State);
349
350             // Gang the link
351             Nb->SetLinkRegang (Node, (*State->PortList)[i].Link, Nb);
352           }
353
354           // Set InLnSt = PHY_OFF in register table.
355           // Set sublink 0 widths to 8 bits
356           if ((*State->PortList)[i].SelWidthOut > 8) {
357             (*State->PortList)[i].SelWidthOut = 8;
358           }
359           if ((*State->PortList)[i].SelWidthIn > 8) {
360             (*State->PortList)[i].SelWidthIn = 8;
361           }
362           WidthOut = State->HtFeatures->ConvertWidthToBits ((*State->PortList)[i].SelWidthOut);
363           WidthIn = State->HtFeatures->ConvertWidthToBits ((*State->PortList)[i].SelWidthIn);
364           Temp = (WidthIn & 7) | ((WidthOut & 7) << 4);
365           Reg = Nb->MakeLinkBase (Node, (*State->PortList)[i].Link, Nb);
366           Reg.Address.Register += HTHOST_LINK_CONTROL_REG;
367           State->HtFeatures->SetHtControlRegisterBits (Reg, 31, 24, &Temp, State);
368         }
369       }
370     }
371   }
372 }
373