AGESA F15: AMD family15 AGESA code
[coreboot.git] / src / vendorcode / amd / agesa / f15 / Proc / HT / Features / htFeatSublinks.c
1 /* $NoKeywords:$ */
2 /**
3  * @file
4  *
5  * SubLink management Routines.
6  *
7  * Contains routines for subLink frequency ratios.
8  *
9  * @xrefitem bom "File Content Label" "Release Content"
10  * @e project:      AGESA
11  * @e sub-project:  HyperTransport
12  * @e \$Revision: 56279 $   @e \$Date: 2011-07-11 13:11:28 -0600 (Mon, 11 Jul 2011) $
13  *
14  */
15 /*
16 *****************************************************************************
17 *
18 * Copyright (C) 2012 Advanced Micro Devices, Inc.
19 * All rights reserved.
20 *
21 * Redistribution and use in source and binary forms, with or without
22 * modification, are permitted provided that the following conditions are met:
23 *     * Redistributions of source code must retain the above copyright
24 *       notice, this list of conditions and the following disclaimer.
25 *     * Redistributions in binary form must reproduce the above copyright
26 *       notice, this list of conditions and the following disclaimer in the
27 *       documentation and/or other materials provided with the distribution.
28 *     * Neither the name of Advanced Micro Devices, Inc. nor the names of
29 *       its contributors may be used to endorse or promote products derived
30 *       from this software without specific prior written permission.
31 *
32 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
34 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
35 * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
36 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
37 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
38 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
39 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
40 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
41 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 *
43 * ***************************************************************************
44 *
45 */
46
47 /*
48  *----------------------------------------------------------------------------
49  *                                MODULES USED
50  *
51  *----------------------------------------------------------------------------
52  */
53
54
55
56 #include "AGESA.h"
57 #include "Ids.h"
58 #include "amdlib.h"
59 #include "Topology.h"
60 #include "htFeat.h"
61 #include "IdsHt.h"
62 #include "htFeatSublinks.h"
63 #include "Filecode.h"
64 CODE_GROUP (G1_PEICC)
65 RDATA_GROUP (G2_PEI)
66
67 #define FILECODE PROC_HT_FEATURES_HTFEATSUBLINKS_FILECODE
68 /*----------------------------------------------------------------------------
69  *                          DEFINITIONS AND MACROS
70  *
71  *----------------------------------------------------------------------------
72  */
73
74 /*----------------------------------------------------------------------------
75  *                           TYPEDEFS AND STRUCTURES
76  *
77  *----------------------------------------------------------------------------
78  */
79
80 typedef struct {
81   UINT8 HiFreq;
82   UINT8 LoFreq;
83 } VALID_RATIO_ITEM;
84
85 STATIC CONST VALID_RATIO_ITEM ROMDATA ValidRatioList[] =
86 {
87   {HT_FREQUENCY_3200M, HT_FREQUENCY_1600M},   // 3200MHz / 1600MHz 2:1
88   {HT_FREQUENCY_3200M, HT_FREQUENCY_800M},    // 3200MHz / 800MHz  4:1
89   {HT_FREQUENCY_3200M, HT_FREQUENCY_400M},    // 3200MHz / 400MHz  8:1
90   {HT_FREQUENCY_2800M, HT_FREQUENCY_1400M},   // 2800MHz / 1400MHz 2:1
91   {HT_FREQUENCY_2400M, HT_FREQUENCY_1200M},   // 2400MHz / 1200MHz 2:1
92   {HT_FREQUENCY_2400M, HT_FREQUENCY_600M},    // 2400MHz /  600MHz 4:1
93   {HT_FREQUENCY_2400M, HT_FREQUENCY_400M},    // 2400MHz /  400MHz 6:1
94   {HT_FREQUENCY_2000M, HT_FREQUENCY_1000M},   // 2000MHz / 1000MHz 2:1
95   {HT_FREQUENCY_1600M, HT_FREQUENCY_800M},    // 1600MHz /  800MHz 2:1
96   {HT_FREQUENCY_1600M, HT_FREQUENCY_400M},    // 1600MHz /  400MHz 4:1
97   {HT_FREQUENCY_1600M, HT_FREQUENCY_200M},    // 1600MHz /  200Mhz 8:1
98   {HT_FREQUENCY_1200M, HT_FREQUENCY_600M},    // 1200MHz /  600MHz 2:1
99   {HT_FREQUENCY_1200M, HT_FREQUENCY_200M},    // 1200MHz /  200MHz 6:1
100   {HT_FREQUENCY_800M,  HT_FREQUENCY_400M},    // 800MHz /  400MHz 2:1
101   {HT_FREQUENCY_800M,  HT_FREQUENCY_200M},    // 800MHz /  200MHz 4:1
102   {HT_FREQUENCY_400M,  HT_FREQUENCY_200M}     // 400MHz /  200MHz 2:1
103 };
104
105 /*----------------------------------------------------------------------------
106  *                        PROTOTYPES OF LOCAL FUNCTIONS
107  *
108  *----------------------------------------------------------------------------
109  */
110
111 /*----------------------------------------------------------------------------
112  *                            EXPORTED FUNCTIONS
113  *
114  *----------------------------------------------------------------------------
115  */
116
117 /*----------------------------------------------------------------------------
118  *                              LOCAL FUNCTIONS
119  *
120  *----------------------------------------------------------------------------
121  */
122
123 /***************************************************************************
124  ***                            Link Optimization                        ***
125  ***************************************************************************/
126
127 /*----------------------------------------------------------------------------------------*/
128 /**
129  * Iterate through all Links, checking the frequency of each subLink pair.
130  *
131  * @HtFeatMethod{::F_SUBLINK_RATIO_FIXUP}
132  *
133  * Make the adjustment to the port list data so that the frequencies
134  * are at a valid ratio, reducing frequency as needed to achieve
135  * this. (All Links support the minimum 200 MHz frequency.)  Repeat
136  * the above until no adjustments are needed.
137  * @note no hardware state changes in this routine.
138  *
139  * @param[in,out]     State     Link state and port list
140  *
141  */
142 VOID
143 SubLinkRatioFixup (
144   IN OUT   STATE_DATA    *State
145   )
146 {
147   UINT8 i;
148   UINT8 j;
149   UINT8 ValidRatioItem;
150   BOOLEAN Changes;
151   BOOLEAN Downgrade;
152   UINT8 HiIndex;
153   UINT8 HiFreq;
154   UINT8 LoFreq;
155
156   UINT32 Temp;
157
158   do {
159     Changes = FALSE;
160     for (i = 0; i < State->TotalLinks*2; i++) {
161       // Must be a CPU Link
162       if ((*State->PortList)[i].Type != PORTLIST_TYPE_CPU) {
163         continue;
164       }
165       // Only look for subLink1's
166       if ((*State->PortList)[i].Link < 4) {
167         continue;
168       }
169
170       for (j = 0; j < State->TotalLinks*2; j++) {
171         // Step 1. Find the matching subLink0
172         if ((*State->PortList)[j].Type != PORTLIST_TYPE_CPU) {
173           continue;
174         }
175         if ((*State->PortList)[j].NodeID != (*State->PortList)[i].NodeID) {
176           continue;
177         }
178         if ((*State->PortList)[j].Link != ((*State->PortList)[i].Link & 0x03)) {
179           continue;
180         }
181
182         // Step 2. Check for an illegal frequency ratio
183         if ((*State->PortList)[i].SelFrequency >= (*State->PortList)[j].SelFrequency) {
184           HiIndex = i;
185           HiFreq = (*State->PortList)[i].SelFrequency;
186           LoFreq = (*State->PortList)[j].SelFrequency;
187         } else {
188           HiIndex = j;
189           HiFreq = (*State->PortList)[j].SelFrequency;
190           LoFreq = (*State->PortList)[i].SelFrequency;
191         }
192
193         // The frequencies are 1:1, no need to do anything
194         if (HiFreq == LoFreq) {
195           break;
196         }
197
198         Downgrade = TRUE;
199
200         for (ValidRatioItem = 0; ValidRatioItem < (sizeof (ValidRatioList) / sizeof (VALID_RATIO_ITEM)); ValidRatioItem++) {
201           if ((HiFreq == ValidRatioList[ValidRatioItem].HiFreq) &&
202               (LoFreq == ValidRatioList[ValidRatioItem].LoFreq)) {
203             Downgrade = FALSE;
204             break;
205           }
206         }
207
208         // Step 3. Downgrade the higher of the two frequencies, and set Changes to FALSE
209         if (Downgrade) {
210           // Although the problem was with the port specified by hiIndex, we need to
211           // Downgrade both ends of the Link.
212           HiIndex = HiIndex & 0xFE; // Select the 'upstream' (i.e. even) port
213
214           Temp = (*State->PortList)[HiIndex].CompositeFrequencyCap;
215
216           // Remove HiFreq from the list of valid frequencies
217           Temp = Temp & ~((UINT32)1 << HiFreq);
218           ASSERT (Temp != 0);
219           (*State->PortList)[HiIndex].CompositeFrequencyCap = (UINT32)Temp;
220           (*State->PortList)[HiIndex + 1].CompositeFrequencyCap = (UINT32)Temp;
221
222           HiFreq = LibAmdBitScanReverse (Temp);
223
224           (*State->PortList)[HiIndex].SelFrequency = HiFreq;
225           (*State->PortList)[HiIndex + 1].SelFrequency = HiFreq;
226
227           Changes = TRUE;
228         }
229       }
230     }
231   } while (Changes); // Repeat until a valid configuration is reached
232 }