AGESA F15: AMD family15 AGESA code
[coreboot.git] / src / vendorcode / amd / agesa / f15 / Proc / HT / htInterfaceNonCoherent.c
1 /* $NoKeywords:$ */
2 /**
3  * @file
4  *
5  * External Interface implementation for non-coherent features.
6  *
7  * Contains routines for accessing the interface to the client BIOS,
8  * for non-coherent features.
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 "htInterfaceNonCoherent.h"
64 #include "htNb.h"
65 #include "Filecode.h"
66 CODE_GROUP (G1_PEICC)
67 RDATA_GROUP (G2_PEI)
68
69 #define FILECODE PROC_HT_HTINTERFACENONCOHERENT_FILECODE
70 /*----------------------------------------------------------------------------
71  *                          DEFINITIONS AND MACROS
72  *
73  *----------------------------------------------------------------------------
74  */
75 #define UNUSED_ZERO_32 ((UINT32)0)
76
77 /*----------------------------------------------------------------------------
78  *                           TYPEDEFS AND STRUCTURES
79  *
80  *----------------------------------------------------------------------------
81  */
82 /*----------------------------------------------------------------------------
83  *                            EXPORTED FUNCTIONS
84  *
85  *----------------------------------------------------------------------------
86  */
87
88 /*----------------------------------------------------------------------------
89  *                              LOCAL FUNCTIONS
90  *
91  *----------------------------------------------------------------------------
92  */
93
94 /*----------------------------------------------------------------------------------------*/
95 /**
96  * Get Manual BUID assignment list.
97  *
98  * @HtInterfaceMethod{::F_GET_MANUAL_BUID_SWAP_LIST}
99  *
100  * This routine is called every time a non-coherent chain is processed.  BUID
101  * assignment may be controlled explicitly on a non-coherent chain. Swaps controls
102  * the BUID assignment and FinalIds provides the device to device Linking.  Device
103  * orientation can be detected automatically, or explicitly.  See documentation for
104  * more details.
105  *
106  * If a manual swap list is not supplied, automatic non-coherent init assigns BUIDs
107  * starting at 1 and incrementing sequentially based on each device's unit count.
108  *
109  * @param[in]    Node    The Node on which this chain is located
110  * @param[in]    Link    The Link on the host for this chain
111  * @param[out]   List    supply a pointer to a list.
112  *                       List is NOT valid unless routine returns TRUE.
113  * @param[in]    State   the input data
114  *
115  * @retval      TRUE     use a manual list
116  * @retval      FALSE    initialize the Link automatically
117  */
118 BOOLEAN
119 GetManualBuidSwapList (
120   IN       UINT8            Node,
121   IN       UINT8            Link,
122      OUT   BUID_SWAP_LIST   **List,
123   IN       STATE_DATA       *State
124   )
125 {
126   MANUAL_BUID_SWAP_LIST *p;
127   BOOLEAN result;
128   UINT8 Socket;
129   UINT8 PackageLink;
130
131   ASSERT ((Node < MAX_NODES) && (List != NULL));
132
133   result = FALSE;
134   Socket = State->HtInterface->GetSocketFromMap (Node, State);
135   PackageLink = State->Nb->GetPackageLink (Node, Link, State->Nb);
136
137   if (State->HtBlock->ManualBuidSwapList != NULL) {
138     p = State->HtBlock->ManualBuidSwapList;
139
140     while (p->Socket != HT_LIST_TERMINAL) {
141       if (((p->Socket == Socket) || (p->Socket == HT_LIST_MATCH_ANY)) &&
142           ((p->Link == PackageLink) || (p->Link == HT_LIST_MATCH_ANY))) {
143         // Found a match implies TRUE, ignore the Link
144         result = TRUE;
145         *List = &(p->SwapList);
146         break;
147       } else {
148         p++;
149       }
150     }
151   }
152   // List is not valid if Result is FALSE.
153   return result;
154 }
155
156 /*----------------------------------------------------------------------------------------*/
157 /**
158  * Override capabilities of a device.
159  *
160  * @HtInterfaceMethod{::F_GET_DEVICE_CAP_OVERRIDE}
161  *
162  * This routine is called once for every Link on every IO device.  Update the width
163  * and frequency capability if needed for this device.  This is used along with
164  * device capabilities, the limit call backs, and northbridge limits to compute the
165  * default settings.  The components of the device's PCI config address are provided,
166  * so its settings can be consulted if need be. The input width and frequency are the
167  * reported device capabilities.
168  *
169  * @param[in]     HostNode      The Node on which this chain is located
170  * @param[in]     HostLink      The Link on the host for this chain
171  * @param[in]     Depth         The Depth in the I/O chain from the Host
172  * @param[in]     PciAddress    The Device's PCI config address (for callout)
173  * @param[in]     DevVenId      The Device's PCI Vendor + Device ID (offset 0x00)
174  * @param[in]     Revision      The Device's PCI Revision
175  * @param[in]     Link          The Device's Link number (0 or 1)
176  * @param[in,out] LinkWidthIn   modify to change the Link Width In
177  * @param[in,out] LinkWidthOut  modify to change the Link Width Out
178  * @param[in,out] FreqCap       modify to change the Link's frequency capability
179  * @param[in,out] Clumping      modify to change unit id clumping capability
180  * @param[in]     State         the input data and config header
181  *
182  */
183 VOID
184 GetDeviceCapOverride (
185   IN       UINT8       HostNode,
186   IN       UINT8       HostLink,
187   IN       UINT8       Depth,
188   IN       PCI_ADDR    PciAddress,
189   IN       UINT32      DevVenId,
190   IN       UINT8       Revision,
191   IN       UINT8       Link,
192   IN OUT   UINT8       *LinkWidthIn,
193   IN OUT   UINT8       *LinkWidthOut,
194   IN OUT   UINT32      *FreqCap,
195   IN OUT   UINT32      *Clumping,
196   IN       STATE_DATA  *State
197   )
198 {
199   DEVICE_CAP_OVERRIDE *p;
200   UINT8 HostSocket;
201   UINT8 PackageLink;
202   DEVICE_CAP_CALLOUT_PARAMS CalloutParams;
203   AGESA_STATUS CalloutStatus;
204
205   ASSERT ((HostNode < MAX_NODES) && (Depth < 32) && ((Link == 0) || (Link == 1)));
206
207   HostSocket = State->HtInterface->GetSocketFromMap (HostNode, State);
208   PackageLink = State->Nb->GetPackageLink (HostNode, HostLink, State->Nb);
209
210   if (State->HtBlock->DeviceCapOverrideList != NULL) {
211     p = State->HtBlock->DeviceCapOverrideList;
212
213     while (p->HostSocket != HT_LIST_TERMINAL) {
214       if (((p->HostSocket == HostSocket) || (p->HostSocket == HT_LIST_MATCH_ANY)) &&
215           ((p->HostLink == PackageLink) || (p->HostLink == HT_LIST_MATCH_ANY)) &&
216           ((p->Depth == Depth) || (p->Depth == HT_LIST_MATCH_ANY)) &&
217           ((p->Link == Link) || (p->Link == HT_LIST_MATCH_ANY)) &&
218           // Found a potential match. Check the additional optional matches.
219           ((p->Options.IsCheckDevVenId == 0) || (p->DevVenId == DevVenId)) &&
220           ((p->Options.IsCheckRevision == 0) || (p->Revision == Revision))) {
221         //
222         // Found a match.  Check what override actions are desired.
223         // Unlike the PCB limit routines, which handle the info returned,
224         // deviceCapOverride is actually overriding the settings, so we need
225         // to check that the field actually has an update.
226         // The Callout is a catch all for situations the data is not up to handling.
227         // It is expected, but not enforced, that either the data overrides are used,
228         // or the callout is used, rather than both.
229         //
230         if (p->Options.IsOverrideWidthIn != 0) {
231           *LinkWidthIn = p->LinkWidthIn;
232         }
233         if (p->Options.IsOverrideWidthOut != 0) {
234           *LinkWidthOut = p->LinkWidthOut;
235         }
236         if (p->Options.IsOverrideFreq != 0) {
237           *FreqCap = p->FreqCap;
238         }
239         if (p->Options.IsOverrideClumping != 0) {
240           *Clumping = p->Clumping;
241         }
242         if (p->Options.IsDoCallout != 0) {
243           //
244           // Pass the actual info being matched, not the matched struct data.
245           // This callout is expected to be built in as part of the options file, and does not use the
246           // callout interface, even though we use the consistent interface declaration for the routine.
247           // So, the first two int parameters have no meaning in this case.
248           // It is not meaningful for the callout to have any status but Success.
249           //
250           CalloutParams.HostSocket = HostSocket;
251           CalloutParams.HostLink = PackageLink;
252           CalloutParams.Depth = Depth;
253           CalloutParams.DevVenId = DevVenId;
254           CalloutParams.Revision = Revision;
255           CalloutParams.Link = Link;
256           CalloutParams.PciAddress = PciAddress;
257           CalloutParams.LinkWidthIn = LinkWidthIn;
258           CalloutParams.LinkWidthOut = LinkWidthOut;
259           CalloutParams.FreqCap = FreqCap;
260           CalloutParams.Clumping = Clumping;
261           CalloutParams.StdHeader = *((AMD_CONFIG_PARAMS *) (State->ConfigHandle));
262           CalloutStatus = p->Callout (UNUSED_ZERO_32, UNUSED_ZERO_32, (VOID *) &CalloutParams);
263           ASSERT (CalloutStatus == AGESA_SUCCESS);
264         }
265         break;
266       } else {
267         p++;
268       }
269     }
270   }
271 }
272
273 /*----------------------------------------------------------------------------------------*/
274 /**
275  * Get limits for non-coherent Links.
276  *
277  * @HtInterfaceMethod{::F_GET_IO_PCB_LIMITS}
278  *
279  * For each non-coherent connection this routine is called once.  Update the
280  * frequency and width if needed for this Link (usually based on board restriction).
281  * This is used with device capabilities, device overrides, and northbridge limits to
282  * compute the default settings. The input width and frequency are valid, but do not
283  * necessarily reflect the minimum setting that will be chosen.
284  *
285  * @param[in]     HostNode                   The Node on which this Link is located
286  * @param[in]     HostLink                   The Link about to be initialized
287  * @param[in]     Depth                      The Depth in the I/O chain from the Host
288  * @param[in,out] DownstreamLinkWidthLimit   modify to change the Link Width In
289  * @param[in,out] UpstreamLinkWidthLimit     modify to change the Link Width Out
290  * @param[in,out] PcbFreqCap                 modify to change the Link's frequency capability
291  * @param[in]     State                      the input data
292  */
293 VOID
294 GetIoPcbLimits (
295   IN       UINT8        HostNode,
296   IN       UINT8        HostLink,
297   IN       UINT8        Depth,
298   IN OUT   UINT8        *DownstreamLinkWidthLimit,
299   IN OUT   UINT8        *UpstreamLinkWidthLimit,
300   IN OUT   UINT32       *PcbFreqCap,
301   IN       STATE_DATA   *State
302   )
303 {
304   IO_PCB_LIMITS *p;
305   UINT8 Socket;
306   UINT8 PackageLink;
307
308   ASSERT ((HostNode < MAX_NODES) && (HostLink < MAX_NODES));
309
310   Socket = State->HtInterface->GetSocketFromMap (HostNode, State);
311   PackageLink = State->Nb->GetPackageLink (HostNode, HostLink, State->Nb);
312
313   if (State->HtBlock->IoPcbLimitsList != NULL) {
314     p = State->HtBlock->IoPcbLimitsList;
315
316     while (p->HostSocket != HT_LIST_TERMINAL) {
317       if (((p->HostSocket == Socket) || (p->HostSocket == HT_LIST_MATCH_ANY)) &&
318           ((p->HostLink == PackageLink) || (p->HostLink == HT_LIST_MATCH_ANY)) &&
319           ((p->Depth == Depth) || (p->Depth == HT_LIST_MATCH_ANY))) {
320         // Found a match, return the override info
321         *DownstreamLinkWidthLimit = p->DownstreamLinkWidthLimit;
322         *UpstreamLinkWidthLimit = p->UpstreamLinkWidthLimit;
323         *PcbFreqCap = p->PcbFreqCap;
324         break;
325       } else {
326         p++;
327       }
328     }
329   }
330 }
331
332 /*----------------------------------------------------------------------------------------*/
333 /**
334  * Manually control bus number assignment.
335  *
336  * @HtInterfaceMethod{::F_GET_OVERRIDE_BUS_NUMBERS}
337  *
338  * This routine is called every time a non-coherent chain is processed.  If a system
339  * can not use the auto Bus numbering feature for non-coherent chain bus assignments,
340  * this routine can provide explicit control.  For each chain, provide the bus number
341  * range to use.
342  *
343  * The outputs SecBus and SubBus are not valid unless this routine returns TRUE
344  *
345  * @param[in]     Node      The Node on which this chain is located
346  * @param[in]     Link      The Link on the host for this chain
347  * @param[out]    SecBus    Secondary Bus number for this non-coherent chain
348  * @param[out]    SubBus    Subordinate Bus number
349  * @param[in]     State     the input data
350  *
351  * @retval        TRUE      this routine is supplying the bus numbers.
352  * @retval        FALSE     use auto Bus numbering, bus outputs not valid.
353  */
354 BOOLEAN
355 GetOverrideBusNumbers (
356   IN       UINT8        Node,
357   IN       UINT8        Link,
358      OUT   UINT8        *SecBus,
359      OUT   UINT8        *SubBus,
360   IN       STATE_DATA   *State
361   )
362 {
363   OVERRIDE_BUS_NUMBERS *p;
364   BOOLEAN result;
365   UINT8 Socket;
366   UINT8 PackageLink;
367
368   ASSERT ((Node < MAX_NODES) && (Link < MAX_NODES));
369
370   result = FALSE;
371   Socket = State->HtInterface->GetSocketFromMap (Node, State);
372   PackageLink = State->Nb->GetPackageLink (Node, Link, State->Nb);
373
374   if (State->HtBlock->OverrideBusNumbersList != NULL) {
375     p = State->HtBlock->OverrideBusNumbersList;
376
377     while (p->Socket != HT_LIST_TERMINAL) {
378       if (((p->Socket == Socket) || (p->Socket == HT_LIST_MATCH_ANY)) &&
379           ((p->Link == PackageLink) || (p->Link == HT_LIST_MATCH_ANY))) {
380         // Found a match, return the bus overrides
381         *SecBus = p->SecBus;
382         *SubBus = p->SubBus;
383         ASSERT (*SubBus > *SecBus);
384         result = TRUE;
385         break;
386       } else {
387         p++;
388       }
389     }
390   }
391   // SecBus, SubBus are not valid if Result is FALSE.
392   return result;
393 }
394