• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /** @file
2    Clock generator setting for multiplatform.
3  
4    Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
5  
6  
7    This program and the accompanying materials are licensed and made available under
8  
9    the terms and conditions of the BSD License that accompanies this distribution.
10  
11    The full text of the license may be found at
12  
13    http://opensource.org/licenses/bsd-license.php.
14  
15  
16  
17    THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
18  
19    WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20  
21  
22  
23  
24  **/
25  
26  #include <BoardClkGens.h>
27  #include <Guid/SetupVariable.h>
28  #include <Ppi/ReadOnlyVariable2.h>
29  #include <Library/BaseMemoryLib.h>
30  
31  #ifndef __GNUC__
32  #pragma optimize( "", off )
33  #endif
34  
35  #define CLKGEN_EN 1
36  #define EFI_DEBUG 1
37  
38  CLOCK_GENERATOR_DETAILS   mSupportedClockGeneratorTable[] =
39  {
40    { ClockGeneratorCk410, CK410_GENERATOR_ID , CK410_GENERATOR_SPREAD_SPECTRUM_BYTE, CK410_GENERATOR_SPREAD_SPECTRUM_BIT },
41    { ClockGeneratorCk505, CK505_GENERATOR_ID , CK505_GENERATOR_SPREAD_SPECTRUM_BYTE, CK505_GENERATOR_SPREAD_SPECTRUM_BIT }
42  };
43  
44  /**
45    Configure the clock generator using the SMBUS PPI services.
46  
47    This function performs a block write, and dumps debug information.
48  
49    @param  PeiServices                General purpose services available to every PEIM.
ConfigureClockGenerator(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_SMBUS_PPI * SmbusPpi,IN CLOCK_GENERATOR_TYPE ClockType,IN UINT8 ClockAddress,IN UINTN ConfigurationTableLength,IN OUT UINT8 * ConfigurationTable)50    @param  ClockType                  Clock generator's model name.
51    @param  ClockAddress               SMBUS address of clock generator.
52    @param  ConfigurationTableLength   Length of configuration table.
53    @param  ConfigurationTable         Pointer of configuration table.
54  
55    @retval EFI_SUCCESS - Operation success.
56  
57  **/
58  EFI_STATUS
59  ConfigureClockGenerator (
60    IN     EFI_PEI_SERVICES              **PeiServices,
61    IN     EFI_PEI_SMBUS_PPI                 *SmbusPpi,
62    IN     CLOCK_GENERATOR_TYPE          ClockType,
63    IN     UINT8                         ClockAddress,
64    IN     UINTN                         ConfigurationTableLength,
65    IN OUT UINT8                         *ConfigurationTable
66    )
67  {
68  
69    EFI_STATUS                    Status;
70    EFI_SMBUS_DEVICE_ADDRESS      SlaveAddress;
71    UINT8                         Buffer[MAX_CLOCK_GENERATOR_BUFFER_LENGTH];
72    UINTN                         Length;
73    EFI_SMBUS_DEVICE_COMMAND      Command;
74  #if CLKGEN_CONFIG_EXTRA
75    UINT8                         j;
76  #endif
77  
78    //
79    // Verify input arguments
80    //
81    ASSERT_EFI_ERROR (ConfigurationTableLength >= 6);
82    ASSERT_EFI_ERROR (ConfigurationTableLength <= MAX_CLOCK_GENERATOR_BUFFER_LENGTH);
83    ASSERT_EFI_ERROR (ClockType < ClockGeneratorMax);
84    ASSERT_EFI_ERROR (ConfigurationTable != NULL);
85  
86    //
87    // Read the clock generator
88    //
89    SlaveAddress.SmbusDeviceAddress = ClockAddress >> 1;
90    Length = sizeof (Buffer);
91    Command = 0;
92    Status = SmbusPpi->Execute (
93      PeiServices,
94      SmbusPpi,
95      SlaveAddress,
96      Command,
97      EfiSmbusReadBlock,
98      FALSE,
99      &Length,
100      Buffer
101      );
102    ASSERT_EFI_ERROR (Status);
103  
104  #ifdef EFI_DEBUG
105    {
106      UINT8 i;
107      for (i = 0; i < sizeof (Buffer); i++) {
108        DEBUG((EFI_D_ERROR, "CK505 default Clock Generator Byte %d: %x\n", i, Buffer[i]));
109      }
110  #if CLKGEN_EN
111      for (i = 0; i < ConfigurationTableLength; i++) {
112        DEBUG((EFI_D_ERROR, "BIOS structure Clock Generator Byte %d: %x\n", i, ConfigurationTable[i]));
113      }
114  #endif
115    }
116  #endif
117  
118    DEBUG((EFI_D_ERROR, "Expected Clock Generator ID is %x, expecting %x\n", mSupportedClockGeneratorTable[ClockType].ClockId,(Buffer[7]&0xF)));
119  
120    //
121    // Program clock generator
122    //
123    Command = 0;
124  #if CLKGEN_EN
125  #if CLKGEN_CONFIG_EXTRA
126    for (j = 0; j < ConfigurationTableLength; j++) {
127      Buffer[j] = ConfigurationTable[j];
128    }
129  
130    Buffer[30] = 0x00;
131  
132    Status = SmbusPpi->Execute (
133      PeiServices,
134      SmbusPpi,
135      SlaveAddress,
136      Command,
137      EfiSmbusWriteBlock,
138      FALSE,
139      &Length,
140      Buffer
141      );
142  #else
143    Status = SmbusPpi->Execute (
144      PeiServices,
145      SmbusPpi,
146      SlaveAddress,
147      Command,
148      EfiSmbusWriteBlock,
149      FALSE,
150      &ConfigurationTableLength,
151      ConfigurationTable
152      );
153  #endif // CLKGEN_CONFIG_EXTRA
154  #else
155      ConfigurationTable[4] = (ConfigurationTable[4] & 0x3) | (Buffer[4] & 0xFC);
156      Command = 4;
157      Length = 1;
158    Status = SmbusPpi->Execute (
159      PeiServices,
160      SmbusPpi,
161      SlaveAddress,
162      Command,
163      EfiSmbusWriteBlock,
164      FALSE,
165      &Length,
166      &ConfigurationTable[4]
167      );
168  #endif //CLKGEN_EN
169    ASSERT_EFI_ERROR (Status);
170  
171    //
172    // Dump contents after write
173    //
174    #ifdef EFI_DEBUG
175      {
176        UINT8   i;
177      SlaveAddress.SmbusDeviceAddress = ClockAddress >> 1;
178      Length = sizeof (Buffer);
179        Command = 0;
180        Status =  SmbusPpi->Execute (
181          PeiServices,
182          SmbusPpi,
183          SlaveAddress,
184          Command,
185          EfiSmbusReadBlock,
186          FALSE,
187          &Length,
188          Buffer
189          );
190  
191        for (i = 0; i < ConfigurationTableLength; i++) {
192          DEBUG((EFI_D_ERROR, "Clock Generator Byte %d: %x\n", i, Buffer[i]));
193        }
194      }
195      #endif
196  
197    return EFI_SUCCESS;
198  }
199  
200  /**
201    Configure the clock generator using the SMBUS PPI services.
202  
203    This function performs a block write, and dumps debug information.
204  
205    @param  PeiServices                General purpose services available to every PEIM.
206    @param  ClockType                  Clock generator's model name.
ReadClockGeneratorID(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_SMBUS_PPI * SmbusPpi,IN UINT8 ClockAddress)207    @param  ClockAddress               SMBUS address of clock generator.
208    @param  ConfigurationTableLength   Length of configuration table.
209    @param  ConfigurationTable         Pointer of configuration table.
210  
211  
212    @retval  EFI_SUCCESS  Operation success.
213  
214  **/
215  UINT8
216  ReadClockGeneratorID (
217    IN     EFI_PEI_SERVICES              **PeiServices,
218    IN     EFI_PEI_SMBUS_PPI                 *SmbusPpi,
219    IN     UINT8                         ClockAddress
220    )
221  {
222    EFI_STATUS                    Status;
223    EFI_SMBUS_DEVICE_ADDRESS      SlaveAddress;
224    UINT8                         Buffer[MAX_CLOCK_GENERATOR_BUFFER_LENGTH];
225    UINTN                         Length;
226    EFI_SMBUS_DEVICE_COMMAND      Command;
227  
228    //
229    // Read the clock generator
230    //
231    SlaveAddress.SmbusDeviceAddress = ClockAddress >> 1;
232    Length = sizeof (Buffer);
233    Command = 0;
234    Status = SmbusPpi->Execute (
235      PeiServices,
236      SmbusPpi,
237      SlaveAddress,
238      Command,
239      EfiSmbusReadBlock,
240      FALSE,
241      &Length,
242      Buffer
243      );
244  
245    //
246    // Sanity check that the requested clock type is present in our supported clocks table
247    //
248    DEBUG((EFI_D_ERROR, "Expected Clock Generator ID is 0x%x\n", Buffer[7]));
249  
250    return (Buffer[7]);
251  }
252  
253  /**
ConfigurePlatformClocks(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_NOTIFY_DESCRIPTOR * NotifyDescriptor,IN VOID * SmbusPpi)254    Configure the clock generator to enable free-running operation.  This keeps
255    the clocks from being stopped when the system enters C3 or C4.
256  
257    @param None
258  
259    @retval EFI_SUCCESS    The function completed successfully.
260  
261  **/
262  EFI_STATUS
263  ConfigurePlatformClocks (
264    IN EFI_PEI_SERVICES           **PeiServices,
265    IN EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,
266    IN VOID                       *SmbusPpi
267    )
268  {
269    //
270    // Comment it out for now
271    // Not supported by Hybrid model.
272    //
273    EFI_STATUS                    Status;
274    UINT8                         *ConfigurationTable;
275  
276    CLOCK_GENERATOR_TYPE          ClockType = ClockGeneratorCk505;
277    UINT8                         ConfigurationTable_Desktop[] = CLOCK_GENERATOR_SETTINGS_DESKTOP;
278    UINT8                         ConfigurationTable_Mobile[] = CLOCK_GENERATOR_SETTINGS_MOBILE;
279    UINT8                         ConfigurationTable_Tablet[] = CLOCK_GENERATOR_SEETINGS_TABLET;
280  
281    EFI_PLATFORM_INFO_HOB         *PlatformInfoHob;
282    BOOLEAN                       EnableSpreadSpectrum;
283    UINT8                         ClockGenID=0;
284    SYSTEM_CONFIGURATION          SystemConfiguration;
285  
286    UINTN                         Length;
287    EFI_SMBUS_DEVICE_COMMAND      Command;
288    EFI_SMBUS_DEVICE_ADDRESS      SlaveAddress;
289    UINT8                         Data;
290  
291    UINT8                         ClockAddress = CLOCK_GENERATOR_ADDRESS;
292    UINTN                         VariableSize;
293    EFI_PEI_READ_ONLY_VARIABLE2_PPI   *Variable;
294  
295    //
296    // Obtain Platform Info from HOB.
297    //
298    Status = GetPlatformInfoHob ((CONST EFI_PEI_SERVICES **) PeiServices, &PlatformInfoHob);
299    ASSERT_EFI_ERROR (Status);
300  
301    DEBUG((EFI_D_ERROR, "PlatformInfo protocol is working in ConfigurePlatformClocks()...%x\n",PlatformInfoHob->PlatformFlavor));
302  
303    //
304    // Locate SMBUS PPI
305    //
306    Status = (**PeiServices).LocatePpi (
307                               (CONST EFI_PEI_SERVICES **) PeiServices,
308                               &gEfiPeiSmbusPpiGuid,
309                               0,
310                               NULL,
311                               &SmbusPpi
312                               );
313    ASSERT_EFI_ERROR (Status);
314  
315    Data  = 0;
316    SlaveAddress.SmbusDeviceAddress = ClockAddress >> 1;
317    Length = 1;
318    Command = 0x87;   //Control Register 7 Vendor ID Check
319    Status = ((EFI_PEI_SMBUS_PPI *) SmbusPpi)->Execute (
320                                                 PeiServices,
321                                                 SmbusPpi,
322                                                 SlaveAddress,
323                                                 Command,
324                                                 EfiSmbusReadByte,
325                                                 FALSE,
326                                                 &Length,
327                                                 &Data
328                                                 );
329  
330    if (EFI_ERROR (Status) || ((Data & 0x0F) != CK505_GENERATOR_ID)) {
331        DEBUG((EFI_D_ERROR, "Clock Generator CK505 Not Present, vendor ID on board is %x\n",(Data & 0x0F)));
332        return EFI_SUCCESS;
333  }
334    ClockGenID = Data & 0x0F;
335  
336    EnableSpreadSpectrum = FALSE;
337    VariableSize = sizeof (SYSTEM_CONFIGURATION);
338    ZeroMem (&SystemConfiguration, sizeof (SYSTEM_CONFIGURATION));
339  
340    Status = (*PeiServices)->LocatePpi (
341                               (CONST EFI_PEI_SERVICES **) PeiServices,
342                               &gEfiPeiReadOnlyVariable2PpiGuid,
343                               0,
344                               NULL,
345                               (VOID **) &Variable
346                               );
347    //
348    // Use normal setup default from NVRAM variable,
349    // the Platform Mode (manufacturing/safe/normal) is handle in PeiGetVariable.
350    //
351    VariableSize = sizeof(SYSTEM_CONFIGURATION);
352    Status = Variable->GetVariable (Variable,
353                                     L"Setup",
354                                     &gEfiSetupVariableGuid,
355                                     NULL,
356                                     &VariableSize,
357                                     &SystemConfiguration);
358    if (EFI_ERROR (Status) || VariableSize != sizeof(SYSTEM_CONFIGURATION)) {
359      //The setup variable is corrupted
360      VariableSize = sizeof(SYSTEM_CONFIGURATION);
361      Status = Variable->GetVariable(Variable,
362                L"SetupRecovery",
363                &gEfiSetupVariableGuid,
364                NULL,
365                &VariableSize,
366                &SystemConfiguration
367                );
368      ASSERT_EFI_ERROR (Status);
369    }
370    if(!EFI_ERROR (Status)){
371      EnableSpreadSpectrum = SystemConfiguration.EnableClockSpreadSpec;
372    }
373  
374    //
375    // Perform platform-specific intialization dependent upon Board ID:
376    //
377    DEBUG((EFI_D_ERROR, "board id is %x, platform id is %x\n",PlatformInfoHob->BoardId,PlatformInfoHob->PlatformFlavor));
378  
379  
380    switch (PlatformInfoHob->BoardId) {
381      case BOARD_ID_MINNOW2:
382      case BOARD_ID_MINNOW2_TURBOT:
383      default:
384        switch(PlatformInfoHob->PlatformFlavor) {
385        case FlavorTablet:
386          ConfigurationTable = ConfigurationTable_Tablet;
387          Length = sizeof (ConfigurationTable_Tablet);
388          break;
389        case FlavorMobile:
390          ConfigurationTable = ConfigurationTable_Mobile;
391          Length = sizeof (ConfigurationTable_Mobile);
392          break;
393        case FlavorDesktop:
394        default:
395          ConfigurationTable = ConfigurationTable_Desktop;
396          Length = sizeof (ConfigurationTable_Desktop);
397          break;
398        }
399      break;
400      }
401  
402    //
403    // Perform common clock initialization:
404    //
405    // Program Spread Spectrum function.
406    //
407    if (EnableSpreadSpectrum)
408    {
409      ConfigurationTable[mSupportedClockGeneratorTable[ClockType].SpreadSpectrumByteOffset] |= mSupportedClockGeneratorTable[ClockType].SpreadSpectrumBitOffset;
410    } else {
411      ConfigurationTable[mSupportedClockGeneratorTable[ClockType].SpreadSpectrumByteOffset] &= ~(mSupportedClockGeneratorTable[ClockType].SpreadSpectrumBitOffset);
412    }
413  
414  
415  #if CLKGEN_EN
416    Status = ConfigureClockGenerator (PeiServices, SmbusPpi, ClockType, ClockAddress, Length, ConfigurationTable);
417    ASSERT_EFI_ERROR (Status);
418  #endif // CLKGEN_EN
419    return EFI_SUCCESS;
420  }
421  
InstallPlatformClocksNotify(IN CONST EFI_PEI_SERVICES ** PeiServices)422  static EFI_PEI_NOTIFY_DESCRIPTOR    mNotifyList[] = {
423    {
424      EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
425      &gEfiPeiSmbusPpiGuid,
426      ConfigurePlatformClocks
427    }
428  };
429  
430  EFI_STATUS
431  InstallPlatformClocksNotify (
432    IN CONST EFI_PEI_SERVICES           **PeiServices
433    )
434  {
435    EFI_STATUS                    Status;
436  
437    DEBUG ((EFI_D_INFO, "InstallPlatformClocksNotify()...\n"));
438  
439    Status = (*PeiServices)->NotifyPpi(PeiServices, &mNotifyList[0]);
440    ASSERT_EFI_ERROR (Status);
441    return EFI_SUCCESS;
442  
443  }
444  
445  #ifndef __GNUC__
446  #pragma optimize( "", on )
447  #endif
448