AGESA F15: AMD family15 AGESA code
[coreboot.git] / src / vendorcode / amd / agesa / f15 / Proc / CPU / Family / 0x15 / OR / cpuF15OrDmi.c
1 /* $NoKeywords:$ */
2 /**
3  * @file
4  *
5  * AMD DMI Record Creation API, and related functions for Fmaily15h Orichi.
6  *
7  * Contains code that produce the DMI related information.
8  *
9  * @xrefitem bom "File Content Label" "Release Content"
10  * @e project:      AGESA
11  * @e sub-project:  CPU/Family/0x15/OR
12  * @e \$Revision: 58290 $   @e \$Date: 2011-08-25 00:02:47 -0600 (Thu, 25 Aug 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 "cpuRegisters.h"
52 #include "cpuFamilyTranslation.h"
53 #include "cpuPstateTables.h"
54 #include "cpuLateInit.h"
55 #include "cpuF15Dmi.h"
56 #include "cpuF15PowerMgmt.h"
57 #include "cpuF15OrPowerMgmt.h"
58 #include "cpuServices.h"
59 #include "Filecode.h"
60 CODE_GROUP (G3_DXE)
61 RDATA_GROUP (G3_DXE)
62
63 #define FILECODE PROC_CPU_FAMILY_0X15_OR_CPUF15ORDMI_FILECODE
64
65
66 /*----------------------------------------------------------------------------------------
67  *                   D E F I N I T I O N S    A N D    M A C R O S
68  *----------------------------------------------------------------------------------------
69  */
70 extern CPU_FAMILY_SUPPORT_TABLE            PstateFamilyServiceTable;
71
72 /*----------------------------------------------------------------------------------------
73  *                  T Y P E D E F S     A N D     S T R U C T U R E S
74  *----------------------------------------------------------------------------------------
75  */
76 CONST CHAR8 ROMDATA str_Opteron_62[] = "AMD Opteron(tm) Processor 62";
77 CONST CHAR8 ROMDATA str_Opteron_42[] = "AMD Opteron(tm) Processor 42";
78 CONST CHAR8 ROMDATA str_Opteron_3[] = "AMD Opteron(tm) Processor 3";
79 CONST CHAR8 ROMDATA str_FX_AM3[] = "AMD FX(tm)-";
80 /*---------------------------------------------------------------------------------------
81  * Processor Family Table
82  *       03Dh = "AMD Opteron(TM) 6200 Processor Family"
83  *       03Eh = "AMD Opteron(TM) 4200 Processor Family"
84  *       03Fh = "AMD FX(TM) Series Processor"
85  *-------------------------------------------------------------------------------------*/
86 CONST CPU_T4_PROC_FAMILY ROMDATA F15OrG34T4ProcFamily[] =
87 {
88   {str_Opteron_62, 0x3D}
89 };
90
91 CONST CPU_T4_PROC_FAMILY ROMDATA F15OrC32T4ProcFamily[] =
92 {
93   {str_Opteron_42, 0x3E}
94 };
95
96 CONST CPU_T4_PROC_FAMILY ROMDATA F15OrAM3T4ProcFamily[] =
97 {
98   {str_FX_AM3, 0x3F},
99   {str_Opteron_3, 0xE4}
100 };
101 /*----------------------------------------------------------------------------------------
102  *           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
103  *----------------------------------------------------------------------------------------
104  */
105 VOID
106 DmiF15OrGetInfo (
107   IN OUT   CPU_TYPE_INFO *CpuInfoPtr,
108   IN       AMD_CONFIG_PARAMS  *StdHeader
109   );
110
111 VOID
112 DmiF15OrGetT4ProcFamily (
113   IN OUT   UINT8 *T4ProcFamily,
114   IN       PROC_FAMILY_TABLE *CpuDmiProcFamilyTable,
115   IN       CPU_TYPE_INFO *CpuInfo,
116   IN       AMD_CONFIG_PARAMS  *StdHeader
117   );
118
119 UINT8
120 DmiF15OrGetVoltage (
121   IN       AMD_CONFIG_PARAMS  *StdHeader
122   );
123
124 VOID
125 DmiF15OrGetMemInfo (
126   IN OUT   CPU_GET_MEM_INFO  *CpuGetMemInfoPtr,
127   IN       AMD_CONFIG_PARAMS  *StdHeader
128   );
129
130 UINT16
131 DmiF15OrGetExtClock (
132   IN       AMD_CONFIG_PARAMS  *StdHeader
133   );
134
135 /*----------------------------------------------------------------------------------------
136  *                          E X P O R T E D    F U N C T I O N S
137  *----------------------------------------------------------------------------------------
138  */
139
140 /* -----------------------------------------------------------------------------*/
141 /**
142  *
143  *  DmiF15OrGetInfo
144  *
145  *    Get CPU type information
146  *
147  *    @param[in,out]  CpuInfoPtr     Pointer to CPU_TYPE_INFO struct.
148  *    @param[in]      StdHeader      Standard Head Pointer
149  *
150  */
151 VOID
152 DmiF15OrGetInfo (
153   IN OUT   CPU_TYPE_INFO *CpuInfoPtr,
154   IN       AMD_CONFIG_PARAMS  *StdHeader
155   )
156 {
157   UINT8 NumOfCoresPerCU;
158   CPUID_DATA CpuId;
159   CPU_SPECIFIC_SERVICES *FamilySpecificServices;
160
161   LibAmdCpuidRead (AMD_CPUID_FMF, &CpuId, StdHeader);
162   CpuInfoPtr->ExtendedFamily = (UINT8) (CpuId.EAX_Reg >> 20) & 0xFF; // bit 27:20
163   CpuInfoPtr->ExtendedModel = (UINT8) (CpuId.EAX_Reg >> 16) & 0xF; // bit 19:16
164   CpuInfoPtr->BaseFamily = (UINT8) (CpuId.EAX_Reg >> 8) & 0xF; // bit 11:8
165   CpuInfoPtr->BaseModel = (UINT8) (CpuId.EAX_Reg >> 4)  & 0xF; // bit 7:4
166   CpuInfoPtr->Stepping = (UINT8) (CpuId.EAX_Reg & 0xF); // bit 3:0
167
168   CpuInfoPtr->PackageType = (UINT8) (CpuId.EBX_Reg >> 28) & 0xF; // bit 31:28
169   // Family 15h Orochi doesn't have CPUID_8000_0001_EBX[BrandId]
170   CpuInfoPtr->BrandId.Pg = 0;
171   CpuInfoPtr->BrandId.String1 = 0;
172   CpuInfoPtr->BrandId.Model = 0;
173   CpuInfoPtr->BrandId.String2 = 0;
174
175   GetCpuServicesOfCurrentCore ((CONST CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
176   CpuInfoPtr->TotalCoreNumber = FamilySpecificServices->GetNumberOfPhysicalCores (FamilySpecificServices, StdHeader);
177   CpuInfoPtr->TotalCoreNumber--;
178
179   LibAmdCpuidRead (AMD_CPUID_ASIZE_PCCOUNT, &CpuId, StdHeader);
180   CpuInfoPtr->EnabledCoreNumber = (UINT8) (CpuId.ECX_Reg & 0xFF); // bit 7:0
181
182   switch (CpuInfoPtr->PackageType) {
183   case OR_SOCKET_AM3:
184     CpuInfoPtr->ProcUpgrade = P_UPGRADE_AM3;
185     break;
186   case OR_SOCKET_G34:
187     CpuInfoPtr->ProcUpgrade = P_UPGRADE_G34;
188     break;
189   case OR_SOCKET_C32:
190     CpuInfoPtr->ProcUpgrade = P_UPGRADE_C32;
191     break;
192   default:
193     CpuInfoPtr->ProcUpgrade = P_UPGRADE_UNKNOWN;
194     break;
195   }
196
197   switch (GetComputeUnitMapping (StdHeader)) {
198   case AllCoresMapping:
199     NumOfCoresPerCU = 1;
200     break;
201   case EvenCoresMapping:
202     NumOfCoresPerCU = 2;
203     break;
204   default:
205     NumOfCoresPerCU = 2;
206   }
207   LibAmdCpuidRead (AMD_CPUID_TLB_L1Cache, &CpuId, StdHeader);
208   CpuInfoPtr->L1CacheSize = (UINT32) (((UINT8) ((CpuId.ECX_Reg >> 24) * NumOfCoresPerCU) + (UINT8) (CpuId.EDX_Reg >> 24)) * (CpuInfoPtr->EnabledCoreNumber + 1) / NumOfCoresPerCU);
209
210   LibAmdCpuidRead (AMD_CPUID_L2L3Cache_L2TLB, &CpuId, StdHeader);
211   CpuInfoPtr->L2CacheSize = (UINT32) ((UINT16) (CpuId.ECX_Reg >> 16) * (CpuInfoPtr->EnabledCoreNumber + 1) / NumOfCoresPerCU);
212 }
213
214 /* -----------------------------------------------------------------------------*/
215 /**
216  *
217  *  DmiF15OrGetT4ProcFamily
218  *
219  *    Get type 4 processor family information
220  *
221  *    @param[in,out]  T4ProcFamily   Pointer to type 4 processor family information.
222  *    @param[in]      *CpuDmiProcFamilyTable  Pointer to DMI family special service
223  *    @param[in]      *CpuInfo       Pointer to CPU_TYPE_INFO struct
224  *    @param[in]      StdHeader      Standard Head Pointer
225  *
226  */
227 VOID
228 DmiF15OrGetT4ProcFamily (
229   IN OUT   UINT8 *T4ProcFamily,
230   IN       PROC_FAMILY_TABLE *CpuDmiProcFamilyTable,
231   IN       CPU_TYPE_INFO *CpuInfo,
232   IN       AMD_CONFIG_PARAMS  *StdHeader
233   )
234 {
235   CHAR8 NameString[49];
236   CONST CHAR8 *DmiString;
237   CONST VOID  *DmiStringTable;
238   UINT8 NumberOfDmiString;
239   UINT8 i;
240
241   // Get name string from MSR_C001_00[30:35]
242   GetNameString (NameString, StdHeader);
243   // Get DMI String
244   DmiStringTable = NULL;
245   switch (CpuInfo->PackageType) {
246   case OR_SOCKET_G34:
247     DmiStringTable = (CONST VOID *) &F15OrG34T4ProcFamily[0];
248     NumberOfDmiString = sizeof (F15OrG34T4ProcFamily) / sizeof (CPU_T4_PROC_FAMILY);
249     break;
250   case OR_SOCKET_C32:
251     DmiStringTable = (CONST VOID *) &F15OrC32T4ProcFamily[0];
252     NumberOfDmiString = sizeof (F15OrC32T4ProcFamily) / sizeof (CPU_T4_PROC_FAMILY);
253     break;
254   case OR_SOCKET_AM3:
255     DmiStringTable = (CONST VOID *) &F15OrAM3T4ProcFamily[0];
256     NumberOfDmiString = sizeof (F15OrAM3T4ProcFamily) / sizeof (CPU_T4_PROC_FAMILY);
257     break;
258   default:
259     DmiStringTable = NULL;
260     NumberOfDmiString = 0;
261     break;
262   }
263
264   // Find out which DMI string matches currect processor's name string
265   *T4ProcFamily = P_FAMILY_UNKNOWN;
266   if ((DmiStringTable != NULL) && (NumberOfDmiString != 0)) {
267     for (i = 0; i < NumberOfDmiString; i++) {
268       DmiString = (((CPU_T4_PROC_FAMILY *) DmiStringTable)[i]).Stringstart;
269       if (IsSourceStrContainTargetStr (NameString, DmiString, StdHeader)) {
270         *T4ProcFamily = (((CPU_T4_PROC_FAMILY *) DmiStringTable)[i]).T4ProcFamilySetting;
271       }
272     }
273   }
274 }
275
276 /* -----------------------------------------------------------------------------*/
277 /**
278  *
279  *  DmiF15OrGetVoltage
280  *
281  *    Get the voltage value according to SMBIOS SPEC's requirement.
282  *
283  *    @param[in]       StdHeader      Standard Head Pointer
284  *
285  *    @retval  Voltage   - CPU Voltage.
286  *
287  */
288 UINT8
289 DmiF15OrGetVoltage (
290   IN       AMD_CONFIG_PARAMS  *StdHeader
291   )
292 {
293   UINT8     MaxVid;
294   UINT8     Voltage;
295   UINT8     NumberBoostStates;
296   UINT32    CurrentNodeNum;
297   UINT64    MsrData;
298   PCI_ADDR  TempAddr;
299   CPB_CTRL_REGISTER CpbCtrl;
300
301   // Voltage = 0x80 + (voltage at boot time * 10)
302   GetCurrentNodeNum (&CurrentNodeNum, StdHeader);
303   TempAddr.AddressValue = MAKE_SBDFO (0, 0, (24 + CurrentNodeNum), FUNC_4, CPB_CTRL_REG);
304   LibAmdPciRead (AccessWidth32, TempAddr, &CpbCtrl, StdHeader);  // F4x15C
305   NumberBoostStates = (UINT8) CpbCtrl.NumBoostStates;
306
307   LibAmdMsrRead ((MSR_PSTATE_0 + NumberBoostStates), &MsrData, StdHeader);
308   MaxVid = (UINT8) (((PSTATE_MSR *)&MsrData)->CpuVid);
309
310
311   if ((MaxVid >= 0x7C) && (MaxVid <= 0x7F)) {
312     Voltage = 0;
313   } else {
314     Voltage = (UINT8) ((15500 - (125 * MaxVid) + 500) / 1000);
315   }
316
317   Voltage += 0x80;
318   return (Voltage);
319 }
320
321 /* -----------------------------------------------------------------------------*/
322 /**
323  *
324  *  DmiF15OrGetMemInfo
325  *
326  *    Get memory information.
327  *
328  *    @param[in,out]  CpuGetMemInfoPtr      Pointer to CPU_GET_MEM_INFO struct.
329  *    @param[in]      StdHeader             Standard Head Pointer
330  *
331  */
332 VOID
333 DmiF15OrGetMemInfo (
334   IN OUT   CPU_GET_MEM_INFO  *CpuGetMemInfoPtr,
335   IN       AMD_CONFIG_PARAMS  *StdHeader
336   )
337 {
338   UINT32 PciData;
339   PCI_ADDR PciAddress;
340
341   CpuGetMemInfoPtr->EccCapable = FALSE;
342   // Orochi uses the different way of access to each DCT
343   //
344   // Switch to DCT 0
345   //
346   PciAddress.AddressValue = MAKE_SBDFO (0, 0 , PCI_DEV_BASE, FUNC_1, 0x10C);
347   LibAmdPciRead (AccessWidth32, PciAddress, &PciData, StdHeader);
348   PciData &= 0xFFFFFFFE;
349   LibAmdPciWrite (AccessWidth32, PciAddress, &PciData, StdHeader);
350
351   PciAddress.AddressValue = MAKE_SBDFO (0, 0 , PCI_DEV_BASE, FUNC_2, 0x90);
352   LibAmdPciRead (AccessWidth32, PciAddress, &PciData, StdHeader);
353   // Check if F2x90[DimmEccEn] is set
354   if ((PciData & 0x00080000) != 0) {
355     CpuGetMemInfoPtr->EccCapable = TRUE;
356   } else {
357     //
358     // Switch to DCT 1
359     //
360     PciAddress.AddressValue = MAKE_SBDFO (0, 0 , PCI_DEV_BASE, FUNC_1, 0x10C);
361     LibAmdPciRead (AccessWidth32, PciAddress, &PciData, StdHeader);
362     PciData |= 0x00000001;
363     LibAmdPciWrite (AccessWidth32, PciAddress, &PciData, StdHeader);
364
365     PciAddress.AddressValue = MAKE_SBDFO (0, 0 , PCI_DEV_BASE, FUNC_2, 0x90);
366     LibAmdPciRead (AccessWidth32, PciAddress, &PciData, StdHeader);
367     // Check if F2x90[DimmEccEn] is set
368     if ((PciData & 0x00080000) != 0) {
369       CpuGetMemInfoPtr->EccCapable = TRUE;
370     }
371   }
372   // Errata #505
373   PciAddress.AddressValue = MAKE_SBDFO (0, 0 , PCI_DEV_BASE, FUNC_1, 0x10C);
374   LibAmdPciRead (AccessWidth32, PciAddress, &PciData, StdHeader);
375   PciData &= 0xFFFFFFFE;
376   LibAmdPciWrite (AccessWidth32, PciAddress, &PciData, StdHeader);
377   // Partition Row Position - 0 is for dual channel memory
378   CpuGetMemInfoPtr->PartitionRowPosition = 0;
379 }
380
381 /* -----------------------------------------------------------------------------*/
382 /**
383  *
384  *  DmiF15OrGetExtClock
385  *
386  *    Get the external clock Speed
387  *
388  *    @param[in]      StdHeader      Standard Head Pointer
389  *
390  *    @retval  ExtClock   - CPU external clock Speed.
391  *
392  */
393 UINT16
394 DmiF15OrGetExtClock (
395   IN       AMD_CONFIG_PARAMS  *StdHeader
396   )
397 {
398   return (EXTERNAL_CLOCK_DFLT);
399 }
400
401 CONST PROC_FAMILY_TABLE ROMDATA ProcFamily15OrDmiTable =
402 {
403 // This table is for Processor family 15h Orochi
404   AMD_FAMILY_15_OR,               // ID for Family 15h Orochi
405   DmiF15OrGetInfo,                // Transfer vectors for family
406   DmiF15OrGetT4ProcFamily,        // Get type 4 processor family information
407   DmiF15OrGetVoltage,             //   specific routines (above)
408   DmiF15GetMaxSpeed,
409   DmiF15OrGetExtClock,
410   DmiF15OrGetMemInfo,             // Get memory information
411   0,
412   NULL
413 };
414
415
416 /*---------------------------------------------------------------------------------------
417  *                          L O C A L    F U N C T I O N S
418  *---------------------------------------------------------------------------------------
419  */