Home | History | Annotate | Download | only in BoardClkGens
      1 /** @file
      2   Clock generator setting for multiplatform.
      3 
      4   Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
      5 
      6   This program and the accompanying materials are licensed and made available under
      8   the terms and conditions of the BSD License that accompanies this distribution.
     10   The full text of the license may be found at
     12   http://opensource.org/licenses/bsd-license.php.
     14 
     16   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     18   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     20 
     22 
     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.
     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.
    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 /**
    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 
    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