AGESA F15: AMD family15 AGESA code
[coreboot.git] / src / vendorcode / amd / agesa / f15 / Proc / HT / Fam10 / htNbSystemFam10.c
1 /* $NoKeywords:$ */
2 /**
3  * @file
4  *
5  * System Tuning Family 10h 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: 56279 $   @e \$Date: 2011-07-11 13:11:28 -0600 (Mon, 11 Jul 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 "htNbSystemFam10.h"
66 #include "Filecode.h"
67 CODE_GROUP (G1_PEICC)
68 RDATA_GROUP (G2_PEI)
69
70 #define FILECODE PROC_HT_FAM10_HTNBSYSTEMFAM10_FILECODE
71 /*----------------------------------------------------------------------------
72  *                          DEFINITIONS AND MACROS
73  *
74  *----------------------------------------------------------------------------
75  */
76
77 /*----------------------------------------------------------------------------
78  *                           TYPEDEFS AND STRUCTURES
79  *
80  *----------------------------------------------------------------------------
81  */
82 /**
83  * Register Fields for an individual link pair.
84  */
85 typedef struct {
86   UINT32 Enable:1;            ///< Enable distribution on this pair.
87   UINT32 Asymmetric:1;        ///< Links are different widths.
88   UINT32 MasterSelect:3;      ///< The master link.
89   UINT32 AlternateSelect:3;   ///< The alternate link.
90 } PAIR_SELECT_FIELDS;
91
92 /**
93  * Register access union for ::PAIR_SELECT_FIELDS.
94  */
95 typedef union {
96   UINT32 Value;               ///< access as a 32 bit value or register.
97   PAIR_SELECT_FIELDS Fields;  ///< access individual fields.
98 } PAIR_SELECT;
99
100 /*----------------------------------------------------------------------------
101  *                        PROTOTYPES OF LOCAL FUNCTIONS
102  *
103  *----------------------------------------------------------------------------
104  */
105
106 /***************************************************************************
107  ***               FAMILY/NORTHBRIDGE SPECIFIC FUNCTIONS                 ***
108  ***************************************************************************/
109
110 /*----------------------------------------------------------------------------------------*/
111 /**
112  * Set the traffic distribution register for the Links provided.
113  *
114  * @HtNbMethod{::F_WRITE_TRAFFIC_DISTRIBUTION}
115  *
116  * @param[in]     Links01   coherent Links from Node 0 to 1
117  * @param[in]     Links10   coherent Links from Node 1 to 0
118  * @param[in]     Nb        this northbridge
119  */
120 VOID
121 Fam10WriteTrafficDistribution (
122   IN       UINT32       Links01,
123   IN       UINT32       Links10,
124   IN       NORTHBRIDGE  *Nb
125   )
126 {
127   UINT32 Temp;
128   PCI_ADDR TrafficDistReg;
129
130   TrafficDistReg.AddressValue = MAKE_SBDFO (MakePciSegmentFromNode (0),
131                                             MakePciBusFromNode (0),
132                                             MakePciDeviceFromNode (0),
133                                             CPU_HTNB_FUNC_00,
134                                             REG_HT_TRAFFIC_DIST_0X164);
135
136   // Node 0
137   // DstLnk
138   LibAmdPciWriteBits (TrafficDistReg, 23, 16, &Links01, Nb->ConfigHandle);
139   // DstNode = 1, cHTPrbDistEn = 1, cHTRspDistEn = 1, cHTReqDistEn = 1
140   Temp = 0x0107;
141   LibAmdPciWriteBits (TrafficDistReg, 15, 0, &Temp, Nb->ConfigHandle);
142
143   TrafficDistReg.AddressValue = MAKE_SBDFO (MakePciSegmentFromNode (1),
144                                             MakePciBusFromNode (1),
145                                             MakePciDeviceFromNode (1),
146                                             CPU_HTNB_FUNC_00,
147                                             REG_HT_TRAFFIC_DIST_0X164);
148
149   // Node 1
150   // DstLnk
151   LibAmdPciWriteBits (TrafficDistReg, 23, 16, &Links10, Nb->ConfigHandle);
152   // DstNode = 0, cHTPrbDistEn = 1, cHTRspDistEn = 1, cHTReqDistEn = 1
153   Temp = 0x0007;
154   LibAmdPciWriteBits (TrafficDistReg, 15, 0, &Temp, Nb->ConfigHandle);
155 }
156
157 /*----------------------------------------------------------------------------------------*/
158 /**
159  * Write a link pair to the link pair distribution and fixups.
160  *
161  * @HtNbMethod{::F_WRITE_LINK_PAIR_DISTRIBUTION}
162  *
163  * Set the links as a pair using the link pair index provided.  Set asymmetric attribute as
164  * provided. If the Master Link is not currently used as the route, fixup the routes for all
165  * nodes which specify the alternate link.
166  *
167  * @param[in]    Node           Set the pair on this node
168  * @param[in]    ConnectedNode  The Node to which this link pair directly connects.
169  * @param[in]    Pair           Using this pair set in the register
170  * @param[in]    Asymmetric     True if different widths
171  * @param[in]    MasterLink     Set this as the master link and in the route
172  * @param[in]    AlternateLink  Set this as the alternate link
173  * @param[in]    Nb             this northbridge
174  *
175  */
176 VOID
177 Fam10WriteLinkPairDistribution (
178   IN       UINT8        Node,
179   IN       UINT8        ConnectedNode,
180   IN       UINT8        Pair,
181   IN       BOOLEAN      Asymmetric,
182   IN       UINT8        MasterLink,
183   IN       UINT8        AlternateLink,
184   IN       NORTHBRIDGE  *Nb
185   )
186 {
187   PCI_ADDR Reg;
188   UINT32 CurrentRoute;
189   UINT32 MasterRoute;
190   UINT32 AlternateRoute;
191   PAIR_SELECT Selection;
192   UINT32 RouteIndex;
193
194   ASSERT ((Node < MAX_NODES) && (ConnectedNode < MAX_NODES));
195   ASSERT (Pair < MAX_LINK_PAIRS);
196   ASSERT (MasterLink < Nb->MaxLinks);
197   ASSERT (AlternateLink < Nb->MaxLinks);
198
199   // Make the master link the route for all routes to or through NodeB, by replacing all occurrences of
200   // Alternate link with Master link.  If routing used the master link, no update is necessary.
201   MasterRoute = (((1 << Nb->BroadcastSelfBit) | Nb->SelfRouteResponseMask | Nb->SelfRouteRequestMask) << (MasterLink + 1));
202   AlternateRoute = (((1 << Nb->BroadcastSelfBit) | Nb->SelfRouteResponseMask | Nb->SelfRouteRequestMask) << (AlternateLink + 1));
203   Reg.AddressValue = MAKE_SBDFO (MakePciSegmentFromNode (Node),
204                                  MakePciBusFromNode (Node),
205                                  MakePciDeviceFromNode (Node),
206                                  CPU_HTNB_FUNC_00,
207                                  REG_ROUTE0_0X40);
208   for (RouteIndex = 0; RouteIndex < MAX_NODES; RouteIndex++) {
209     Reg.Address.Register = REG_ROUTE0_0X40 + (RouteIndex * 4);
210     LibAmdPciReadBits (Reg, 31, 0, &CurrentRoute, Nb->ConfigHandle);
211     if ((CurrentRoute & AlternateRoute) != 0) {
212       // Since Master and Alternate are redundant, the route must use one or the other but not both.
213       ASSERT ((CurrentRoute & MasterRoute) == 0);
214       // Set the master route for Request, Response or Broadcast only if the alternate was used for that case.
215       // Example, use of a link as a broadcast link is typically not the same route register as its use for Request, Response.
216       CurrentRoute = ((CurrentRoute & ~AlternateRoute) |
217                       ((((CurrentRoute & AlternateRoute) >> (AlternateLink + 1)) << (MasterLink + 1)) & MasterRoute));
218       LibAmdPciWriteBits (Reg, 31, 0, &CurrentRoute, Nb->ConfigHandle);
219     }
220   }
221
222   // Set the Link Pair and Enable it
223   Selection.Fields.Enable = 1;
224   Selection.Fields.Asymmetric = Asymmetric;
225   Selection.Fields.MasterSelect = MasterLink;
226   Selection.Fields.AlternateSelect = AlternateLink;
227   Reg.AddressValue = MAKE_SBDFO (MakePciSegmentFromNode (Node),
228                                  MakePciBusFromNode (Node),
229                                  MakePciDeviceFromNode (Node),
230                                  CPU_HTNB_FUNC_00,
231                                  REG_HT_LINK_PAIR_DIST_0X1E0);
232   LibAmdPciWriteBits (
233     Reg,
234     ((PAIR_SELECT_OFFSET * (Pair + 1)) - 1),
235     (PAIR_SELECT_OFFSET * Pair),
236     &Selection.Value,
237     Nb->ConfigHandle
238     );
239 }
240
241 /*----------------------------------------------------------------------------------------*/
242 /**
243  * Family 10h specific tunings.
244  *
245  * @HtNbMethod{::F_BUFFER_OPTIMIZATIONS}
246  *
247  * Buffer tunings are inherently northbridge specific. Check for specific configs
248  * which require adjustments and apply any standard workarounds to this Node.
249  *
250  * @param[in]     Node   the Node to tune
251  * @param[in]     State  global state
252  * @param[in]     Nb     this northbridge
253  */
254 VOID
255 Fam10BufferOptimizations (
256   IN       UINT8       Node,
257   IN       STATE_DATA  *State,
258   IN       NORTHBRIDGE *Nb
259   )
260 {
261   UINT32 Temp;
262   PCI_ADDR currentPtr;
263   PCI_ADDR GangedReg;
264   UINT8 i;
265
266   ASSERT (Node < MAX_NODES);
267
268   //
269   // Link to XCS Token Count Tuning
270   //
271   // For each active Link that we reganged (so this unfortunately can't go into the PCI reg
272   // table), we have to switch the Link to XCS Token Counts to the ganged state.
273   // We do this here for the non - uma case, which is to write the values that would have
274   // been power on defaults if the Link was ganged at cold reset.
275   //
276   for (i = 0; i < (State->TotalLinks * 2); i++) {
277     if (((*State->PortList)[i].NodeID == Node) && ((*State->PortList)[i].Type == PORTLIST_TYPE_CPU)) {
278       // If the Link is greater than 4, this is a subLink 1, so it is not reganged.
279       if ((*State->PortList)[i].Link < 4) {
280         currentPtr.AddressValue = MAKE_SBDFO (MakePciSegmentFromNode (Node),
281                                               MakePciBusFromNode (Node),
282                                               MakePciDeviceFromNode (Node),
283                                               CPU_NB_FUNC_03,
284                                               REG_NB_LINK_XCS_TOKEN0_3X148 + (4 * (*State->PortList)[i].Link)
285           );
286         if ((*State->PortList)[i].SelRegang) {
287           // Handle all the regang Token count adjustments
288
289           // SubLink 0: [Probe0tok] = 2 [Rsp0tok] = 2 [PReq0tok] = 2 [Req0tok] = 2
290           Temp = 0xAA;
291           LibAmdPciWriteBits (currentPtr, 7, 0, &Temp, Nb->ConfigHandle);
292           // SubLink 1: [Probe1tok] = 0 [Rsp1tok] = 0 [PReq1tok] = 0 [Req1tok] = 0
293           Temp = 0;
294           LibAmdPciWriteBits (currentPtr, 23, 16, &Temp, Nb->ConfigHandle);
295           // [FreeTok] = 3
296           Temp = 3;
297           LibAmdPciWriteBits (currentPtr, 15, 14, &Temp, Nb->ConfigHandle);
298
299         } else {
300           // Read the regang bit in hardware
301           GangedReg.AddressValue = MAKE_SBDFO (MakePciSegmentFromNode ((*State->PortList)[i].NodeID),
302                                                MakePciBusFromNode ((*State->PortList)[i].NodeID),
303                                                MakePciDeviceFromNode ((*State->PortList)[i].NodeID),
304                                                CPU_HTNB_FUNC_00,
305                                                REG_HT_LINK_EXT_CONTROL0_0X170 + (4 * (*State->PortList)[i].Link));
306           LibAmdPciReadBits (GangedReg, 0, 0, &Temp, Nb->ConfigHandle);
307           if (Temp == 1) {
308             // handle a minor adjustment for strapped ganged Links.  If SelRegang is false we
309             // didn't do the regang, so if the bit is on then it's hardware strapped.
310             //
311
312             // [FreeTok] = 3
313             Temp = 3;
314             LibAmdPciWriteBits (currentPtr, 15, 14, &Temp, Nb->ConfigHandle);
315           }
316         }
317       }
318     }
319   }
320 }
321
322 /*----------------------------------------------------------------------------------------*/
323 /**
324  * Family 10h specific tunings.
325  *
326  * @HtNbMethod{::F_BUFFER_OPTIMIZATIONS}
327  *
328  * Buffer tunings are inherently northbridge specific. Check for specific configs
329  * which require adjustments and apply any standard workarounds to this Node.
330  *
331  * @param[in]     Node   the Node to tune
332  * @param[in]     State  global state
333  * @param[in]     Nb     this northbridge
334  */
335 VOID
336 Fam10RevDBufferOptimizations (
337   IN       UINT8       Node,
338   IN       STATE_DATA  *State,
339   IN       NORTHBRIDGE *Nb
340   )
341 {
342   UINT32 Temp;
343   PCI_ADDR Reg;
344   UINT8 i;
345   FINAL_LINK_STATE FinalLinkState;
346   UINT32 WidthIn;
347   UINT32 WidthOut;
348
349   ASSERT (Node < MAX_NODES);
350
351   //
352   // Internal link fixup.
353   // When powering off internal link 2, a performance optimization may be possible where its buffers
354   // can be made available to the external paired sublink.  If the conditions are met, do the fix up here.
355   //
356   for (i = 0; i < (State->TotalLinks * 2); i++) {
357     if (((*State->PortList)[i].NodeID == Node) && ((*State->PortList)[i].Type == PORTLIST_TYPE_CPU)) {
358       // Is this a sublink 0 paired with internal link 2?
359       if (((*State->PortList)[i].Link < 4) &&
360           (Nb->GetPackageLink (Node, ((*State->PortList)[i].Link + 4), Nb) == HT_LIST_MATCH_INTERNAL_LINK_2)) {
361         FinalLinkState = State->HtInterface->GetIgnoreLink (Node, ((*State->PortList)[i].Link + 4), Nb->DefaultIgnoreLinkList, State);
362         // Are we ignoring the internal link 2 with Power Off?
363         if (FinalLinkState == POWERED_OFF) {
364           // Read the regang bit in hardware.
365           Reg.AddressValue = MAKE_SBDFO (MakePciSegmentFromNode (Node),
366                                          MakePciBusFromNode (Node),
367                                          MakePciDeviceFromNode (Node),
368                                          CPU_HTNB_FUNC_00,
369                                          REG_HT_LINK_EXT_CONTROL0_0X170 + (4 * (*State->PortList)[i].Link));
370           LibAmdPciReadBits (Reg, 0, 0, &Temp, Nb->ConfigHandle);
371           // If it's already ganged, skip to the width fix up.
372           if (Temp == 0) {
373             // Clear EndOfChain / XmitOff on internal sublink
374             Reg = Nb->MakeLinkBase (Node, ((*State->PortList)[i].Link + 4), Nb);
375             Reg.Address.Register += HTHOST_LINK_CONTROL_REG;
376             Temp = 0;
377             State->HtFeatures->SetHtControlRegisterBits (Reg, 7, 6, &Temp, State);
378
379             // Gang the link
380             Nb->SetLinkRegang (Node, (*State->PortList)[i].Link, Nb);
381           }
382
383           // Set InLnSt = PHY_OFF in register table.
384           // Set sublink 0 widths to 8 bits
385           if ((*State->PortList)[i].SelWidthOut > 8) {
386             (*State->PortList)[i].SelWidthOut = 8;
387           }
388           if ((*State->PortList)[i].SelWidthIn > 8) {
389             (*State->PortList)[i].SelWidthIn = 8;
390           }
391           WidthOut = State->HtFeatures->ConvertWidthToBits ((*State->PortList)[i].SelWidthOut);
392           WidthIn = State->HtFeatures->ConvertWidthToBits ((*State->PortList)[i].SelWidthIn);
393           Temp = (WidthIn & 7) | ((WidthOut & 7) << 4);
394           Reg = Nb->MakeLinkBase (Node, (*State->PortList)[i].Link, Nb);
395           Reg.Address.Register += HTHOST_LINK_CONTROL_REG;
396           State->HtFeatures->SetHtControlRegisterBits (Reg, 31, 24, &Temp, State);
397         }
398       }
399     }
400   }
401 }
402