AGESA F15: AMD family15 AGESA code
[coreboot.git] / src / vendorcode / amd / agesa / f15 / Proc / CPU / cpuPowerMgmtMultiSocket.c
1 /* $NoKeywords:$ */
2 /**
3  * @file
4  *
5  * AMD CPU Power Management Multisocket Functions.
6  *
7  * Contains code for doing power management for multisocket CPUs
8  *
9  * @xrefitem bom "File Content Label" "Release Content"
10  * @e project:      AGESA
11  * @e sub-project:  CPU
12  * @e \$Revision: 56322 $   @e \$Date: 2011-07-11 16:51:42 -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  *                             M O D U L E S    U S E D
48  *----------------------------------------------------------------------------------------
49  */
50
51 #include "AGESA.h"
52 #include "amdlib.h"
53 #include "Ids.h"
54 #include "cpuRegisters.h"
55 #include "GeneralServices.h"
56 #include "cpuServices.h"
57 #include "cpuApicUtilities.h"
58 #include "cpuFamilyTranslation.h"
59 #include "cpuPowerMgmtSystemTables.h"
60 #include "cpuPowerMgmtMultiSocket.h"
61 #include "GeneralServices.h"
62 #include "Filecode.h"
63 CODE_GROUP (G1_PEICC)
64 RDATA_GROUP (G2_PEI)
65
66 #define FILECODE PROC_CPU_CPUPOWERMGMTMULTISOCKET_FILECODE
67 /*----------------------------------------------------------------------------------------
68  *                   D E F I N I T I O N S    A N D    M A C R O S
69  *----------------------------------------------------------------------------------------
70  */
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
77 /*----------------------------------------------------------------------------------------
78  *           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
79  *----------------------------------------------------------------------------------------
80  */
81 VOID
82 STATIC
83 GetNextEvent (
84   IN OUT   VOID  *EventLogEntryPtr,
85   IN       AMD_CONFIG_PARAMS *StdHeader
86   );
87
88 /*----------------------------------------------------------------------------------------
89  *                          E X P O R T E D    F U N C T I O N S
90  *----------------------------------------------------------------------------------------
91  */
92
93 /*---------------------------------------------------------------------------------------*/
94 /**
95  * Multisocket BSC call to start all system core 0s to perform a standard AP_TASK.
96  *
97  * This function loops through all possible socket locations, starting core 0 of
98  * each populated socket to perform the passed in AP_TASK.  After starting all
99  * other core 0s, the BSC will perform the AP_TASK as well.  This must be run by
100  * the system BSC only.
101  *
102  * @param[in]  TaskPtr           Function descriptor
103  * @param[in]  StdHeader         Config handle for library and services
104  * @param[in]  ConfigParams      AMD entry point's CPU parameter structure
105  *
106  */
107 VOID
108 RunCodeOnAllSystemCore0sMulti (
109   IN       AP_TASK *TaskPtr,
110   IN       AMD_CONFIG_PARAMS *StdHeader,
111   IN       VOID *ConfigParams
112   )
113 {
114   UINT32 BscSocket;
115   UINT32 BscModule;
116   UINT32 BscCoreNum;
117   UINT8  Socket;
118   UINT32 NumberOfSockets;
119   AGESA_STATUS DummyStatus;
120
121   ASSERT (IsBsp (StdHeader, &DummyStatus));
122
123   NumberOfSockets = GetPlatformNumberOfSockets ();
124
125   IdentifyCore (StdHeader, &BscSocket, &BscModule, &BscCoreNum, &DummyStatus);
126
127   for (Socket = 0; Socket < NumberOfSockets; Socket++) {
128     if (Socket != BscSocket) {
129       if (IsProcessorPresent (Socket, StdHeader)) {
130         ApUtilRunCodeOnSocketCore (Socket, 0, TaskPtr, StdHeader);
131       }
132     }
133   }
134   ApUtilTaskOnExecutingCore (TaskPtr, StdHeader, ConfigParams);
135 }
136
137
138 /*---------------------------------------------------------------------------------------*/
139 /**
140  * Multisocket BSC call to determine the maximum number of steps that any single
141  * processor needs to execute.
142  *
143  * This function loops through all possible socket locations, gathering the number
144  * of power management steps each populated socket requires, and returns the
145  * highest number.
146  *
147  * @param[out] NumSystemSteps    Maximum number of system steps required
148  * @param[in]  StdHeader         Config handle for library and services
149  *
150  */
151 VOID
152 GetNumberOfSystemPmStepsPtrMulti (
153      OUT   UINT8 *NumSystemSteps,
154   IN       AMD_CONFIG_PARAMS *StdHeader
155   )
156 {
157   UINT8  NumberOfSteps;
158   UINT32 NumberOfSockets;
159   UINT32 Socket;
160   SYS_PM_TBL_STEP *Ignored;
161   CPU_SPECIFIC_SERVICES *FamilySpecificServices;
162
163   NumberOfSockets = GetPlatformNumberOfSockets ();
164   *NumSystemSteps = 0;
165
166   for (Socket = 0; Socket < NumberOfSockets; Socket++) {
167     if (IsProcessorPresent (Socket, StdHeader)) {
168       GetCpuServicesOfSocket (Socket, (const CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
169       FamilySpecificServices->GetSysPmTableStruct (FamilySpecificServices, (CONST VOID **) &Ignored, &NumberOfSteps, StdHeader);
170       if (NumberOfSteps > *NumSystemSteps) {
171         *NumSystemSteps = NumberOfSteps;
172       }
173     }
174   }
175 }
176
177
178 /*---------------------------------------------------------------------------------------*/
179 /**
180  * Multisocket call to determine the frequency that the northbridges must run.
181  *
182  * This function loops through all possible socket locations, comparing the
183  * maximum NB frequencies to determine the slowest.  This function also
184  * determines if all coherent NB frequencies are equivalent.
185  *
186  * @param[in]  NbPstate                    NB P-state number to check (0 = fastest)
187  * @param[in]  PlatformConfig              Platform profile/build option config structure.
188  * @param[out] SystemNbCofNumerator        NB frequency numerator for the system in MHz
189  * @param[out] SystemNbCofDenominator      NB frequency denominator for the system
190  * @param[out] SystemNbCofsMatch           Whether or not all NB frequencies are equivalent
191  * @param[out] NbPstateIsEnabledOnAllCPUs  Whether or not NbPstate is valid on all CPUs
192  * @param[in]  StdHeader                   Config handle for library and services
193  *
194  * @retval     TRUE                        At least one processor has NbPstate enabled.
195  * @retval     FALSE                       NbPstate is disabled on all CPUs
196  *
197  */
198 BOOLEAN
199 GetSystemNbCofMulti (
200   IN       UINT32 NbPstate,
201   IN       PLATFORM_CONFIGURATION *PlatformConfig,
202      OUT   UINT32 *SystemNbCofNumerator,
203      OUT   UINT32 *SystemNbCofDenominator,
204      OUT   BOOLEAN *SystemNbCofsMatch,
205      OUT   BOOLEAN *NbPstateIsEnabledOnAllCPUs,
206   IN       AMD_CONFIG_PARAMS *StdHeader
207   )
208 {
209   UINT32   Socket;
210   UINT8    Module;
211   UINT32   CurrentNbCof;
212   UINT32   CurrentDivisor;
213   UINT32   CurrentFreq;
214   UINT32   LowFrequency;
215   UINT32   Ignored32;
216   BOOLEAN  FirstCofNotFound;
217   BOOLEAN  NbPstateDisabled;
218   BOOLEAN  IsNbPstateEnabledOnAny;
219   PCI_ADDR PciAddress;
220   AGESA_STATUS Ignored;
221   CPU_SPECIFIC_SERVICES *FamilySpecificServices;
222
223   // Find the slowest NB COF in the system & whether or not all are equivalent
224   LowFrequency = 0xFFFFFFFF;
225   *SystemNbCofsMatch = TRUE;
226   *NbPstateIsEnabledOnAllCPUs = FALSE;
227   IsNbPstateEnabledOnAny = FALSE;
228   FirstCofNotFound = TRUE;
229   NbPstateDisabled = FALSE;
230   for (Socket = 0; Socket < GetPlatformNumberOfSockets (); Socket++) {
231     if (IsProcessorPresent (Socket, StdHeader)) {
232       GetCpuServicesOfSocket (Socket, (const CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
233       for (Module = 0; Module < GetPlatformNumberOfModules (); Module++) {
234         if (GetPciAddress (StdHeader, Socket, Module, &PciAddress, &Ignored)) {
235           break;
236         }
237       }
238       if (FamilySpecificServices->GetNbPstateInfo (FamilySpecificServices,
239                                                    PlatformConfig,
240                                                    &PciAddress,
241                                                    NbPstate,
242                                                    &CurrentNbCof,
243                                                    &CurrentDivisor,
244                                                    &Ignored32,
245                                                    StdHeader)) {
246         ASSERT (CurrentDivisor != 0);
247         CurrentFreq = (CurrentNbCof / CurrentDivisor);
248         if (FirstCofNotFound) {
249           *SystemNbCofNumerator = CurrentNbCof;
250           *SystemNbCofDenominator = CurrentDivisor;
251           LowFrequency = CurrentFreq;
252           IsNbPstateEnabledOnAny = TRUE;
253           if (!NbPstateDisabled) {
254             *NbPstateIsEnabledOnAllCPUs = TRUE;
255           }
256           FirstCofNotFound = FALSE;
257         } else {
258           if (CurrentFreq != LowFrequency) {
259             *SystemNbCofsMatch = FALSE;
260             if (CurrentFreq < LowFrequency) {
261               LowFrequency = CurrentFreq;
262               *SystemNbCofNumerator = CurrentNbCof;
263               *SystemNbCofDenominator = CurrentDivisor;
264             }
265           }
266         }
267       } else {
268         NbPstateDisabled = TRUE;
269         *NbPstateIsEnabledOnAllCPUs = FALSE;
270       }
271     }
272   }
273   return IsNbPstateEnabledOnAny;
274 }
275
276
277 /*---------------------------------------------------------------------------------------*/
278 /**
279  * Multisocket call to determine if the BIOS is responsible for updating the
280  * northbridge operating frequency and voltage.
281  *
282  * This function loops through all possible socket locations, checking whether
283  * any populated sockets require NB COF VID programming.
284  *
285  * @param[in]  StdHeader         Config handle for library and services
286  *
287  * @retval     TRUE    BIOS needs to set up NB frequency and voltage
288  * @retval     FALSE   BIOS does not need to set up NB frequency and voltage
289  *
290  */
291 BOOLEAN
292 GetSystemNbCofVidUpdateMulti (
293   IN       AMD_CONFIG_PARAMS *StdHeader
294   )
295 {
296   UINT8    Module;
297   UINT32   Socket;
298   UINT32   NumberOfSockets;
299   BOOLEAN  IgnoredBool;
300   BOOLEAN  AtLeast1RequiresUpdate;
301   PCI_ADDR PciAddress;
302   AGESA_STATUS Ignored;
303   CPU_SPECIFIC_SERVICES *FamilySpecificServices;
304
305   NumberOfSockets = GetPlatformNumberOfSockets ();
306
307   AtLeast1RequiresUpdate = FALSE;
308   for (Socket = 0; Socket < NumberOfSockets; Socket++) {
309     if (IsProcessorPresent (Socket, StdHeader)) {
310       GetCpuServicesOfSocket (Socket, (const CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
311       for (Module = 0; Module < GetPlatformNumberOfModules (); Module++) {
312         if (GetPciAddress (StdHeader, (UINT8) Socket, Module, &PciAddress, &Ignored)) {
313           break;
314         }
315       }
316       if (FamilySpecificServices->IsNbCofInitNeeded (FamilySpecificServices, &PciAddress, &IgnoredBool, StdHeader)) {
317         AtLeast1RequiresUpdate = TRUE;
318         break;
319       }
320     }
321   }
322   return AtLeast1RequiresUpdate;
323 }
324
325
326 /*---------------------------------------------------------------------------------------*/
327 /**
328  * Multisocket call to determine the most severe AGESA_STATUS return value after
329  * processing the power management initialization tables.
330  *
331  * This function loops through all possible socket locations, collecting any
332  * power management initialization errors that may have occurred.  These errors
333  * are transferred from the core 0s of the socket in which the errors occurred
334  * to the BSC's heap.  The BSC's heap is then searched for the most severe error
335  * that occurred, and returns it.  This function must be called by the BSC only.
336  *
337  * @param[in]  StdHeader         Config handle for library and services
338  *
339  * @return     The most severe error code from power management init
340  *
341  */
342 AGESA_STATUS
343 GetEarlyPmErrorsMulti (
344   IN       AMD_CONFIG_PARAMS *StdHeader
345   )
346 {
347   UINT16 i;
348   UINT32 BscSocket;
349   UINT32 BscModule;
350   UINT32 BscCoreNum;
351   UINT32 Socket;
352   UINT32 NumberOfSockets;
353   AP_TASK      TaskPtr;
354   AGESA_EVENT  EventLogEntry;
355   AGESA_STATUS ReturnCode;
356   AGESA_STATUS DummyStatus;
357
358   ASSERT (IsBsp (StdHeader, &ReturnCode));
359
360   ReturnCode = AGESA_SUCCESS;
361   EventLogEntry.EventClass = AGESA_SUCCESS;
362   EventLogEntry.EventInfo = 0;
363   EventLogEntry.DataParam1 = 0;
364   EventLogEntry.DataParam2 = 0;
365   EventLogEntry.DataParam3 = 0;
366   EventLogEntry.DataParam4 = 0;
367
368   NumberOfSockets = GetPlatformNumberOfSockets ();
369   IdentifyCore (StdHeader, &BscSocket, &BscModule, &BscCoreNum, &DummyStatus);
370
371   TaskPtr.FuncAddress.PfApTaskI = GetNextEvent;
372   TaskPtr.DataTransfer.DataSizeInDwords = SIZE_IN_DWORDS (AGESA_EVENT);
373   TaskPtr.DataTransfer.DataPtr = &EventLogEntry;
374   TaskPtr.DataTransfer.DataTransferFlags = 0;
375   TaskPtr.ExeFlags = WAIT_FOR_CORE | RETURN_PARAMS;
376   for (Socket = 0; Socket < NumberOfSockets; Socket++) {
377     if (Socket != BscSocket) {
378       if (IsProcessorPresent (Socket, StdHeader)) {
379         do {
380           ApUtilRunCodeOnSocketCore ((UINT8)Socket, (UINT8) 0, &TaskPtr, StdHeader);
381           if ((EventLogEntry.EventInfo & CPU_EVENT_PM_EVENT_MASK) == CPU_EVENT_PM_EVENT_CLASS) {
382             PutEventLog (
383               EventLogEntry.EventClass,
384               EventLogEntry.EventInfo,
385               EventLogEntry.DataParam1,
386               EventLogEntry.DataParam2,
387               EventLogEntry.DataParam3,
388               EventLogEntry.DataParam4,
389               StdHeader
390               );
391           }
392         } while (EventLogEntry.EventInfo != 0);
393       }
394     }
395   }
396
397   for (i = 0; PeekEventLog (&EventLogEntry, i, StdHeader); i++) {
398     if ((EventLogEntry.EventInfo & CPU_EVENT_PM_EVENT_MASK) == CPU_EVENT_PM_EVENT_CLASS) {
399       if (EventLogEntry.EventClass > ReturnCode) {
400         ReturnCode = EventLogEntry.EventClass;
401       }
402     }
403   }
404   return (ReturnCode);
405 }
406
407 /**
408  * Multisocket call to loop through all possible socket locations and Nb Pstates,
409  * comparing the NB frequencies to determine the slowest system and P0 frequency
410  *
411  * @param[in]  PlatformConfig      Platform profile/build option config structure.
412  * @param[out] MinSysNbFreq        NB frequency numerator for the system in MHz
413  * @param[out] MinP0NbFreq         NB frequency numerator for P0 in MHz
414  * @param[in]  StdHeader           Config handle for library and services
415  */
416 VOID
417 GetMinNbCofMulti (
418   IN       PLATFORM_CONFIGURATION *PlatformConfig,
419      OUT   UINT32                 *MinSysNbFreq,
420      OUT   UINT32                 *MinP0NbFreq,
421   IN       AMD_CONFIG_PARAMS      *StdHeader
422   )
423 {
424   UINT32                Socket;
425   UINT32                Module;
426   UINT32                CurrMinFreq;
427   UINT32                CurrMaxFreq;
428   PCI_ADDR              PciAddress;
429   AGESA_STATUS          Ignored;
430   CPU_SPECIFIC_SERVICES *FamilySpecificServices;
431
432   *MinSysNbFreq = 0xFFFFFFFF;
433   *MinP0NbFreq  = 0xFFFFFFFF;
434
435   for (Socket = 0; Socket < GetPlatformNumberOfSockets (); Socket++) {
436     if (IsProcessorPresent (Socket, StdHeader)) {
437       GetCpuServicesOfSocket (Socket, (const CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
438       for (Module = 0; Module < GetPlatformNumberOfModules (); Module++) {
439         if (GetPciAddress (StdHeader, Socket, Module, &PciAddress, &Ignored )) {
440           break;
441         }
442       }
443
444
445       FamilySpecificServices->GetMinMaxNbFrequency (FamilySpecificServices,
446                                                       PlatformConfig,
447                                                       &PciAddress,
448                                                       &CurrMinFreq,
449                                                       &CurrMaxFreq,
450                                                       StdHeader);
451       // Determine the slowest NB Pmin frequency
452       if (CurrMinFreq < *MinSysNbFreq) {
453         *MinSysNbFreq = CurrMinFreq;
454       }
455
456       // Determine the slowest NB P0 frequency
457       if (CurrMaxFreq < *MinP0NbFreq) {
458         *MinP0NbFreq = CurrMaxFreq;
459       }
460     }
461   }
462 }
463
464 /*---------------------------------------------------------------------------------------*/
465 /**
466  * Get PCI Config Space Address for the current running core.
467  *
468  * @param[out]   PciAddress   The Processor's PCI Config Space address (Function 0, Register 0)
469  * @param[in]    StdHeader    Header for library and services.
470  *
471  * @retval       TRUE         The core is present, PCI Address valid
472  * @retval       FALSE        The core is not present, PCI Address not valid.
473  */
474 BOOLEAN
475 GetCurrPciAddrMulti (
476      OUT   PCI_ADDR               *PciAddress,
477   IN       AMD_CONFIG_PARAMS      *StdHeader
478   )
479 {
480   UINT8        Node;
481   UINT32       Socket;
482   UINT32       Module;
483   UINT32       Core;
484   BOOLEAN      Result;
485   AGESA_STATUS IgnoredSts;
486
487   Result = TRUE;
488
489   IdentifyCore (StdHeader, &Socket, &Module, &Core, &IgnoredSts);
490
491   ASSERT (Socket < MAX_SOCKETS);
492   ASSERT (Module < MAX_DIES);
493
494   if (GetNodeId (Socket, Module, &Node, StdHeader)) {
495     // Socket is populated
496     PciAddress->AddressValue = MAKE_SBDFO (0, 0, 24, 0, 0);
497     PciAddress->Address.Device = PciAddress->Address.Device + Node;
498   } else {
499     // Socket is not populated
500     PciAddress->AddressValue = ILLEGAL_SBDFO;
501     Result = FALSE;
502   }
503
504   return Result;
505 }
506
507 /*---------------------------------------------------------------------------------------*/
508 /**
509  *  Writes to all nodes on the executing core's socket.
510  *
511  *  @param[in]     PciAddress    The Function and Register to update
512  *  @param[in]     Mask          The bitwise AND mask to apply to the current register value
513  *  @param[in]     Data          The bitwise OR mask to apply to the current register value
514  *  @param[in]     StdHeader     Header for library and services.
515  *
516  */
517 VOID
518 ModifyCurrSocketPciMulti (
519   IN       PCI_ADDR               *PciAddress,
520   IN       UINT32                 Mask,
521   IN       UINT32                 Data,
522   IN       AMD_CONFIG_PARAMS      *StdHeader
523   )
524 {
525   UINT32 Socket;
526   UINT32 Module;
527   UINT32 Core;
528   UINT32 LocalPciRegister;
529   AGESA_STATUS AgesaStatus;
530   PCI_ADDR Reg;
531
532   IdentifyCore (StdHeader, &Socket, &Module, &Core, &AgesaStatus);
533
534   for (Module = 0; Module < (UINT8)GetPlatformNumberOfModules (); Module++) {
535     if (GetPciAddress (StdHeader, Socket, Module, &Reg, &AgesaStatus)) {
536       Reg.Address.Function = PciAddress->Address.Function;
537       Reg.Address.Register = PciAddress->Address.Register;
538       LibAmdPciRead (AccessWidth32, Reg, &LocalPciRegister, StdHeader);
539       LocalPciRegister &= Mask;
540       LocalPciRegister |= Data;
541       LibAmdPciWrite (AccessWidth32, Reg, &LocalPciRegister, StdHeader);
542     }
543   }
544 }
545
546 /*---------------------------------------------------------------------------------------
547  *                           L O C A L    F U N C T I O N S
548  *---------------------------------------------------------------------------------------
549  */
550
551 /*---------------------------------------------------------------------------------------*/
552 /**
553  * AP task to return the next event log entry to the BSC.
554  *
555  * This function calls to the event log manager to retrieve the next error out
556  * of the heap.
557  *
558  * @param[out] EventLogEntryPtr  The AP's next event log entry
559  * @param[in]  StdHeader         Config handle for library and services
560  *
561  */
562 VOID
563 STATIC
564 GetNextEvent (
565   IN OUT   VOID  *EventLogEntryPtr,
566   IN       AMD_CONFIG_PARAMS *StdHeader
567   )
568 {
569   GetEventLog ((AGESA_EVENT *) EventLogEntryPtr, StdHeader);
570 }