AGESA F15: AMD family15 AGESA code
[coreboot.git] / src / vendorcode / amd / agesa / f15 / Proc / CPU / cpuBrandId.c
1 /* $NoKeywords:$ */
2 /**
3  * @file
4  *
5  * AMD CPU BrandId related functions.
6  *
7  * Contains code that provides CPU BrandId information
8  *
9  * @xrefitem bom "File Content Label" "Release Content"
10  * @e project:      AGESA
11  * @e sub-project:  CPU
12  * @e \$Revision: 56279 $   @e \$Date: 2011-07-11 13:11:28 -0600 (Mon, 11 Jul 2011) $
13  *
14  */
15 /*****************************************************************************
16  *
17  * Copyright (C) 2012 Advanced Micro Devices, Inc.
18  * All rights reserved.
19  *
20  * Redistribution and use in source and binary forms, with or without
21  * modification, are permitted provided that the following conditions are met:
22  *     * Redistributions of source code must retain the above copyright
23  *       notice, this list of conditions and the following disclaimer.
24  *     * Redistributions in binary form must reproduce the above copyright
25  *       notice, this list of conditions and the following disclaimer in the
26  *       documentation and/or other materials provided with the distribution.
27  *     * Neither the name of Advanced Micro Devices, Inc. nor the names of
28  *       its contributors may be used to endorse or promote products derived
29  *       from this software without specific prior written permission.
30  *
31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
32  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
33  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
34  * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
35  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
36  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
38  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
40  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41  *
42  ******************************************************************************
43  */
44
45 /*----------------------------------------------------------------------------------------
46  *                             M O D U L E S    U S E D
47  *----------------------------------------------------------------------------------------
48  */
49 #include "AGESA.h"
50 #include "amdlib.h"
51 #include "OptionPstate.h"
52 #include "cpuRegisters.h"
53 #include "cpuFamilyTranslation.h"
54 #include "cpuEarlyInit.h"
55 #include "cpuRegisters.h"
56 #include "heapManager.h"
57 #include "GeneralServices.h"
58 #include "Filecode.h"
59 CODE_GROUP (G1_PEICC)
60 RDATA_GROUP (G2_PEI)
61 #define FILECODE PROC_CPU_CPUBRANDID_FILECODE
62 /*----------------------------------------------------------------------------------------
63  *                   D E F I N I T I O N S    A N D    M A C R O S
64  *----------------------------------------------------------------------------------------
65  */
66
67 /*----------------------------------------------------------------------------------------
68  *                  T Y P E D E F S     A N D     S T R U C T U  R E S
69  *----------------------------------------------------------------------------------------
70  */
71 CONST CHAR8 ROMDATA strEngSample[] = "AMD Engineering Sample";
72 CONST CHAR8 ROMDATA strTtkSample[] = "AMD Thermal Test Kit";
73 CONST CHAR8 ROMDATA strUnknown[] = "AMD Processor Model Unknown";
74
75 CONST AMD_CPU_BRAND ROMDATA EngSample_Str = {0, 0, 0, SOCKET_IGNORE, strEngSample, sizeof (strEngSample)};
76 CONST AMD_CPU_BRAND ROMDATA TtkSample_Str = {0, 1, 0, SOCKET_IGNORE, strTtkSample, sizeof (strTtkSample)};
77 CONST AMD_CPU_BRAND ROMDATA Dflt_Str1 = {0, 0, 0, SOCKET_IGNORE, strUnknown, sizeof (strUnknown)};
78 CONST AMD_CPU_BRAND ROMDATA Dflt_Str2 = {0, 0, 0, SOCKET_IGNORE, DR_NO_STRING, DR_NO_STRING};
79
80
81 /*----------------------------------------------------------------------------------------
82  *           P R O T O T Y P E S     O F     L O C A L     F U  N C T I O N S
83  *----------------------------------------------------------------------------------------
84  */
85 VOID
86 SetBrandIdRegistersAtEarly (
87   IN       CPU_SPECIFIC_SERVICES  *FamilyServices,
88   IN       AMD_CPU_EARLY_PARAMS   *EarlyParams,
89   IN       AMD_CONFIG_PARAMS      *StdHeader
90   );
91
92 /*----------------------------------------------------------------------------------------
93  *                          E X P O R T E D    F U N C T I O N S
94  *----------------------------------------------------------------------------------------
95  */
96
97 /*---------------------------------------------------------------------------------------*/
98 /**
99  * Program BrandID registers (CPUIDNameStringPtr[0-5])
100  *
101  * This function determines the appropriate brand string for the executing
102  * core, and programs the namestring MSRs.
103  *
104  * @param[in,out] StdHeader   Config handle for library and services.
105  *
106  */
107 VOID
108 SetBrandIdRegisters (
109   IN OUT   AMD_CONFIG_PARAMS *StdHeader
110   )
111 {
112   UINT8   SocketIndex;
113   UINT8   SuffixStatus;
114   UINT8   TableElements;
115   UINT8   TableEntryCount;
116   UINT8   TableEntryIndex;
117   CHAR8   TempChar;
118   CHAR8   *NameStringPtr;
119   CHAR8   *SuffixStringPtr;
120   CHAR8   *BrandStringPtr;
121   CHAR8   *TempNameCharPtr;
122   UINT32  MsrIndex;
123   UINT32  Quotient;
124   UINT32  Remainder;
125   UINT64  *MsrNameStringPtrPtr;
126   CPUID_DATA    CpuId;
127   CPU_LOGICAL_ID CpuLogicalId;
128   CPU_BRAND_TABLE *SocketTableEntry;
129   CPU_BRAND_TABLE **SocketTableEntry1;
130   AMD_CPU_BRAND *SocketTablePtr;
131   AMD_CPU_BRAND_DATA Data;
132   ALLOCATE_HEAP_PARAMS AllocHeapParams;
133   CPU_SPECIFIC_SERVICES *FamilySpecificServices;
134
135   SuffixStatus = 0;
136   FamilySpecificServices = NULL;
137   SocketTablePtr = NULL;
138   SocketTableEntry = NULL;
139
140   GetCpuServicesOfCurrentCore ((CONST CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
141   // Step1: Allocate 48 bytes from Heap space
142   AllocHeapParams.RequestedBufferSize = CPU_BRAND_ID_LENGTH;
143   AllocHeapParams.BufferHandle = AMD_BRAND_ID_BUFFER_HANDLE;
144   AllocHeapParams.Persist = HEAP_LOCAL_CACHE;
145   if (HeapAllocateBuffer (&AllocHeapParams, StdHeader) == AGESA_SUCCESS) {
146     // Clear NameBuffer
147     BrandStringPtr = (CHAR8 *) AllocHeapParams.BufferPtr;
148     LibAmdMemFill (BrandStringPtr, 0, CPU_BRAND_ID_LENGTH, StdHeader);
149   } else {
150     PutEventLog (
151       AGESA_ERROR,
152       CPU_ERROR_BRANDID_HEAP_NOT_AVAILABLE,
153       0, 0, 0, 0, StdHeader
154       );
155     return;
156   }
157
158   // Step2: Get brandid from model number and model string
159   LibAmdCpuidRead (AMD_CPUID_FMF, &CpuId, StdHeader);
160
161   // Step3: Figure out Socket/Page/Model/String1/String2/Core Number
162   Data.String2 = (UINT8) (CpuId.EBX_Reg & 0x0f);
163   Data.Model   = (UINT8) ((CpuId.EBX_Reg >> 4) & 0x7f);
164   Data.String1 = (UINT8) ((CpuId.EBX_Reg >> 11) & 0x0f);
165   Data.Page    = (UINT8) ((CpuId.EBX_Reg >> 15) & 0x01);
166   Data.Socket  = (UINT8) ((CpuId.EBX_Reg >> 28) & 0x0f);
167   Data.Cores = FamilySpecificServices->GetNumberOfPhysicalCores (FamilySpecificServices, StdHeader);
168
169   // Step4: If NN = 0, we have an engineering sample, no suffix; then jump to Step6
170   if (Data.Model == 0) {
171     if (Data.Page == 0) {
172       SocketTablePtr = (AMD_CPU_BRAND *)&EngSample_Str;
173     } else {
174       SocketTablePtr = (AMD_CPU_BRAND *)&TtkSample_Str;
175     }
176   } else {
177
178     // Model is not equal to zero, so decrement it
179     // For family 10 if PkgType[3:0] is greater than or equal to 2h and families >= 12h
180     GetLogicalIdOfCurrentCore (&CpuLogicalId, StdHeader);
181     if ((((CpuLogicalId.Family & AMD_FAMILY_10) != 0) && (Data.Socket >= DR_SOCKET_S1G3)) ||
182         ((CpuLogicalId.Family & AMD_FAMILY_GE_12) != 0)) {
183       Data.Model--;
184     }
185
186     // Step5: Search for String1 (there can be only 1)
187     FamilySpecificServices->GetBrandString1 (FamilySpecificServices, (const VOID **) &SocketTableEntry, &TableEntryCount, StdHeader);
188     SocketTableEntry1 = (CPU_BRAND_TABLE **) SocketTableEntry;
189     for (TableEntryIndex = 0; ((TableEntryIndex < TableEntryCount)
190          && (SuffixStatus == 0)); TableEntryIndex++, SocketTableEntry1++) {
191       if (*SocketTableEntry1 == NULL) {
192         break;
193       }
194       SocketTablePtr = (AMD_CPU_BRAND *) (*SocketTableEntry1)->Table;
195       TableElements = (*SocketTableEntry1)->NumberOfEntries;
196       for (SocketIndex = 0; (SocketIndex < TableElements)
197            && SuffixStatus == 0; SocketIndex++) {
198         if ((SocketTablePtr->Page == Data.Page) &&
199             (SocketTablePtr->Index == Data.String1) &&
200             (SocketTablePtr->Socket == Data.Socket) &&
201             (SocketTablePtr->Cores == Data.Cores)) {
202           SuffixStatus = 1;
203         } else {
204           SocketTablePtr++;
205         }
206       }
207     }
208     if (SuffixStatus == 0) {
209       SocketTablePtr = (AMD_CPU_BRAND *)&Dflt_Str1;  // We did not find one, make 'Unknown'
210     }
211   }
212
213   // Step6: Copy String into NameBuffer
214   // We now have data structure pointing to correct type in (*SocketTablePtr)
215   LibAmdMemCopy  (BrandStringPtr,
216                   (CHAR8 *)SocketTablePtr->Stringstart,
217                   SocketTablePtr->Stringlength,
218                   StdHeader);
219
220   // Step7: Get suffix, determine addition to BRANDSPEED
221   if (SuffixStatus != 0) {
222     // Turn our value into a decimal string
223     // We have a value like 37d which we need to turn into '3' '7'
224     // Divide by 10, store remainder as an ASCII char on stack, repeat until Quotient is 0
225     NameStringPtr = BrandStringPtr + SocketTablePtr->Stringlength - 1;
226     TempNameCharPtr = NameStringPtr;
227     Quotient = Data.Model;
228     do {
229       Remainder = Quotient % 10;
230       Quotient = Quotient / 10;
231       *TempNameCharPtr++ = (CHAR8) (Remainder + '0');   // Put suffix into our NameBuffer
232     } while (Quotient != 0);
233     if (Data.Model < 10) {
234       *TempNameCharPtr++ = '0';
235     }
236
237     // Step8: Reverse the string sequence and copy into NameBuffer
238     SuffixStringPtr = TempNameCharPtr--;
239     while (NameStringPtr < TempNameCharPtr) {
240       TempChar = *NameStringPtr;
241       *NameStringPtr = *TempNameCharPtr;
242       *TempNameCharPtr = TempChar;
243       NameStringPtr++;
244       TempNameCharPtr--;
245     }
246
247     // Step9: Search for String2
248     SuffixStatus = 0;
249     FamilySpecificServices->GetBrandString2 (FamilySpecificServices, (const VOID **) &SocketTableEntry, &TableEntryCount, StdHeader);
250     SocketTableEntry1 = (CPU_BRAND_TABLE **) SocketTableEntry;
251     for (TableEntryIndex = 0; ((TableEntryIndex < TableEntryCount)
252          && (SuffixStatus == 0)); TableEntryIndex++, SocketTableEntry1++) {
253       if (*SocketTableEntry1 == NULL) {
254         break;
255       }
256       SocketTablePtr = (AMD_CPU_BRAND *) (*SocketTableEntry1)->Table;
257       TableElements = (*SocketTableEntry1)->NumberOfEntries;
258       for (SocketIndex = 0; (SocketIndex < TableElements)
259            && SuffixStatus == 0; SocketIndex++) {
260         if ((SocketTablePtr->Page == Data.Page) &&
261             (SocketTablePtr->Index == Data.String2) &&
262             (SocketTablePtr->Socket == Data.Socket) &&
263             (SocketTablePtr->Cores == Data.Cores)) {
264           SuffixStatus = 1;
265         } else {
266           SocketTablePtr++;
267         }
268       }
269     }
270     if (SuffixStatus == 0) {
271       SocketTablePtr = (AMD_CPU_BRAND *)&Dflt_Str2;
272     }
273
274     // Step10: Copy String2 into our NameBuffer
275     if (SocketTablePtr->Stringlength != 0) {
276       LibAmdMemCopy (SuffixStringPtr,
277                       (CHAR8 *)SocketTablePtr->Stringstart,
278                       SocketTablePtr->Stringlength,
279                       StdHeader);
280     }
281   }
282
283   // Step11: Put values into name MSRs,  Always write the full 48 bytes
284   MsrNameStringPtrPtr = (UINT64 *) BrandStringPtr;
285   for (MsrIndex = MSR_CPUID_NAME_STRING0; MsrIndex <= MSR_CPUID_NAME_STRING5; MsrIndex++) {
286     LibAmdMsrWrite (MsrIndex, MsrNameStringPtrPtr, StdHeader);
287     MsrNameStringPtrPtr++;
288   }
289   HeapDeallocateBuffer (AMD_BRAND_ID_BUFFER_HANDLE, StdHeader);
290 }
291
292 /*---------------------------------------------------------------------------------------*/
293 /**
294  * Program BrandID registers (CPUIDNameStringPtr[0-5])
295  *
296  * This function acts as a wrapper for calling the SetBrandIdRegisters
297  * routine at AmdInitEarly.
298  *
299  *  @param[in]   FamilyServices      The current Family Specific Services.
300  *  @param[in]   EarlyParams         Service parameters.
301  *  @param[in]   StdHeader           Config handle for library and services.
302  *
303  */
304 VOID
305 SetBrandIdRegistersAtEarly (
306   IN       CPU_SPECIFIC_SERVICES  *FamilyServices,
307   IN       AMD_CPU_EARLY_PARAMS   *EarlyParams,
308   IN       AMD_CONFIG_PARAMS      *StdHeader
309   )
310 {
311   AGESA_TESTPOINT (TpProcCpuSetBrandID, StdHeader);
312   SetBrandIdRegisters (StdHeader);
313 }