summaryrefslogtreecommitdiff
path: root/Vlv2TbltDevicePkg/Library/MultiPlatformLib/BoardClkGens/BoardClkGens.c
diff options
context:
space:
mode:
Diffstat (limited to 'Vlv2TbltDevicePkg/Library/MultiPlatformLib/BoardClkGens/BoardClkGens.c')
-rw-r--r--Vlv2TbltDevicePkg/Library/MultiPlatformLib/BoardClkGens/BoardClkGens.c426
1 files changed, 426 insertions, 0 deletions
diff --git a/Vlv2TbltDevicePkg/Library/MultiPlatformLib/BoardClkGens/BoardClkGens.c b/Vlv2TbltDevicePkg/Library/MultiPlatformLib/BoardClkGens/BoardClkGens.c
new file mode 100644
index 0000000000..1fc731205b
--- /dev/null
+++ b/Vlv2TbltDevicePkg/Library/MultiPlatformLib/BoardClkGens/BoardClkGens.c
@@ -0,0 +1,426 @@
+/** @file
+ Clock generator setting for multiplatform.
+
+ Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials are licensed and made available under
+ the terms and conditions of the BSD License that accompanies this distribution.
+ The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+**/
+
+#include <BoardClkGens.h>
+#include <Guid/SetupVariable.h>
+#include <Ppi/ReadOnlyVariable2.h>
+#include <Library/BaseMemoryLib.h>
+
+#ifndef __GNUC__
+#pragma optimize( "", off )
+#endif
+
+#define CLKGEN_EN 1
+#define EFI_DEBUG 1
+
+CLOCK_GENERATOR_DETAILS mSupportedClockGeneratorTable[] =
+{
+ { ClockGeneratorCk410, CK410_GENERATOR_ID , CK410_GENERATOR_SPREAD_SPECTRUM_BYTE, CK410_GENERATOR_SPREAD_SPECTRUM_BIT },
+ { ClockGeneratorCk505, CK505_GENERATOR_ID , CK505_GENERATOR_SPREAD_SPECTRUM_BYTE, CK505_GENERATOR_SPREAD_SPECTRUM_BIT }
+};
+
+/**
+ Configure the clock generator using the SMBUS PPI services.
+
+ This function performs a block write, and dumps debug information.
+
+ @param PeiServices General purpose services available to every PEIM.
+ @param ClockType Clock generator's model name.
+ @param ClockAddress SMBUS address of clock generator.
+ @param ConfigurationTableLength Length of configuration table.
+ @param ConfigurationTable Pointer of configuration table.
+
+ @retval EFI_SUCCESS - Operation success.
+
+**/
+EFI_STATUS
+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
+ )
+{
+
+ EFI_STATUS Status;
+ EFI_SMBUS_DEVICE_ADDRESS SlaveAddress;
+ UINT8 Buffer[MAX_CLOCK_GENERATOR_BUFFER_LENGTH];
+ UINTN Length;
+ EFI_SMBUS_DEVICE_COMMAND Command;
+#if CLKGEN_CONFIG_EXTRA
+ UINT8 j;
+#endif
+
+ //
+ // Verify input arguments
+ //
+ ASSERT_EFI_ERROR (ConfigurationTableLength >= 6);
+ ASSERT_EFI_ERROR (ConfigurationTableLength <= MAX_CLOCK_GENERATOR_BUFFER_LENGTH);
+ ASSERT_EFI_ERROR (ClockType < ClockGeneratorMax);
+ ASSERT_EFI_ERROR (ConfigurationTable != NULL);
+
+ //
+ // Read the clock generator
+ //
+ SlaveAddress.SmbusDeviceAddress = ClockAddress >> 1;
+ Length = sizeof (Buffer);
+ Command = 0;
+ Status = SmbusPpi->Execute (
+ PeiServices,
+ SmbusPpi,
+ SlaveAddress,
+ Command,
+ EfiSmbusReadBlock,
+ FALSE,
+ &Length,
+ Buffer
+ );
+ ASSERT_EFI_ERROR (Status);
+
+#ifdef EFI_DEBUG
+ {
+ UINT8 i;
+ for (i = 0; i < sizeof (Buffer); i++) {
+ DEBUG((EFI_D_ERROR, "CK505 default Clock Generator Byte %d: %x\n", i, Buffer[i]));
+ }
+#if CLKGEN_EN
+ for (i = 0; i < ConfigurationTableLength; i++) {
+ DEBUG((EFI_D_ERROR, "BIOS structure Clock Generator Byte %d: %x\n", i, ConfigurationTable[i]));
+ }
+#endif
+ }
+#endif
+
+ DEBUG((EFI_D_ERROR, "Expected Clock Generator ID is %x, expecting %x\n", mSupportedClockGeneratorTable[ClockType].ClockId,(Buffer[7]&0xF)));
+
+ //
+ // Program clock generator
+ //
+ Command = 0;
+#if CLKGEN_EN
+#if CLKGEN_CONFIG_EXTRA
+ for (j = 0; j < ConfigurationTableLength; j++) {
+ Buffer[j] = ConfigurationTable[j];
+ }
+
+ Buffer[30] = 0x00;
+
+ Status = SmbusPpi->Execute (
+ PeiServices,
+ SmbusPpi,
+ SlaveAddress,
+ Command,
+ EfiSmbusWriteBlock,
+ FALSE,
+ &Length,
+ Buffer
+ );
+#else
+ Status = SmbusPpi->Execute (
+ PeiServices,
+ SmbusPpi,
+ SlaveAddress,
+ Command,
+ EfiSmbusWriteBlock,
+ FALSE,
+ &ConfigurationTableLength,
+ ConfigurationTable
+ );
+#endif // CLKGEN_CONFIG_EXTRA
+#else
+ ConfigurationTable[4] = (ConfigurationTable[4] & 0x3) | (Buffer[4] & 0xFC);
+ Command = 4;
+ Length = 1;
+ Status = SmbusPpi->Execute (
+ PeiServices,
+ SmbusPpi,
+ SlaveAddress,
+ Command,
+ EfiSmbusWriteBlock,
+ FALSE,
+ &Length,
+ &ConfigurationTable[4]
+ );
+#endif //CLKGEN_EN
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Dump contents after write
+ //
+ #ifdef EFI_DEBUG
+ {
+ UINT8 i;
+ SlaveAddress.SmbusDeviceAddress = ClockAddress >> 1;
+ Length = sizeof (Buffer);
+ Command = 0;
+ Status = SmbusPpi->Execute (
+ PeiServices,
+ SmbusPpi,
+ SlaveAddress,
+ Command,
+ EfiSmbusReadBlock,
+ FALSE,
+ &Length,
+ Buffer
+ );
+
+ for (i = 0; i < ConfigurationTableLength; i++) {
+ DEBUG((EFI_D_ERROR, "Clock Generator Byte %d: %x\n", i, Buffer[i]));
+ }
+ }
+ #endif
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Configure the clock generator using the SMBUS PPI services.
+
+ This function performs a block write, and dumps debug information.
+
+ @param PeiServices General purpose services available to every PEIM.
+ @param ClockType Clock generator's model name.
+ @param ClockAddress SMBUS address of clock generator.
+ @param ConfigurationTableLength Length of configuration table.
+ @param ConfigurationTable Pointer of configuration table.
+
+
+ @retval EFI_SUCCESS Operation success.
+
+**/
+UINT8
+ReadClockGeneratorID (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_SMBUS_PPI *SmbusPpi,
+ IN UINT8 ClockAddress
+ )
+{
+ EFI_STATUS Status;
+ EFI_SMBUS_DEVICE_ADDRESS SlaveAddress;
+ UINT8 Buffer[MAX_CLOCK_GENERATOR_BUFFER_LENGTH];
+ UINTN Length;
+ EFI_SMBUS_DEVICE_COMMAND Command;
+
+ //
+ // Read the clock generator
+ //
+ SlaveAddress.SmbusDeviceAddress = ClockAddress >> 1;
+ Length = sizeof (Buffer);
+ Command = 0;
+ Status = SmbusPpi->Execute (
+ PeiServices,
+ SmbusPpi,
+ SlaveAddress,
+ Command,
+ EfiSmbusReadBlock,
+ FALSE,
+ &Length,
+ Buffer
+ );
+
+ //
+ // Sanity check that the requested clock type is present in our supported clocks table
+ //
+ DEBUG((EFI_D_ERROR, "Expected Clock Generator ID is 0x%x\n", Buffer[7]));
+
+ return (Buffer[7]);
+}
+
+/**
+ Configure the clock generator to enable free-running operation. This keeps
+ the clocks from being stopped when the system enters C3 or C4.
+
+ @param None
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+ConfigurePlatformClocks (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *SmbusPpi
+ )
+{
+ //
+ // Comment it out for now
+ // Not supported by Hybrid model.
+ //
+ EFI_STATUS Status;
+ UINT8 *ConfigurationTable;
+
+ CLOCK_GENERATOR_TYPE ClockType = ClockGeneratorCk505;
+ UINT8 ConfigurationTable_Desktop[] = CLOCK_GENERATOR_SETTINGS_DESKTOP;
+ UINT8 ConfigurationTable_Mobile[] = CLOCK_GENERATOR_SETTINGS_MOBILE;
+ UINT8 ConfigurationTable_Tablet[] = CLOCK_GENERATOR_SEETINGS_TABLET;
+
+ EFI_PLATFORM_INFO_HOB *PlatformInfoHob;
+ BOOLEAN EnableSpreadSpectrum;
+ UINT8 ClockGenID=0;
+ SYSTEM_CONFIGURATION SystemConfiguration;
+
+ UINTN Length;
+ EFI_SMBUS_DEVICE_COMMAND Command;
+ EFI_SMBUS_DEVICE_ADDRESS SlaveAddress;
+ UINT8 Data;
+
+ UINT8 ClockAddress = CLOCK_GENERATOR_ADDRESS;
+ UINTN VariableSize;
+ EFI_PEI_READ_ONLY_VARIABLE2_PPI *Variable;
+
+ //
+ // Obtain Platform Info from HOB.
+ //
+ Status = GetPlatformInfoHob ((CONST EFI_PEI_SERVICES **) PeiServices, &PlatformInfoHob);
+ ASSERT_EFI_ERROR (Status);
+
+ DEBUG((EFI_D_ERROR, "PlatformInfo protocol is working in ConfigurePlatformClocks()...%x\n",PlatformInfoHob->PlatformFlavor));
+
+ //
+ // Locate SMBUS PPI
+ //
+ Status = (**PeiServices).LocatePpi (
+ (CONST EFI_PEI_SERVICES **) PeiServices,
+ &gEfiPeiSmbusPpiGuid,
+ 0,
+ NULL,
+ &SmbusPpi
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Data = 0;
+ SlaveAddress.SmbusDeviceAddress = ClockAddress >> 1;
+ Length = 1;
+ Command = 0x87; //Control Register 7 Vendor ID Check
+ Status = ((EFI_PEI_SMBUS_PPI *) SmbusPpi)->Execute (
+ PeiServices,
+ SmbusPpi,
+ SlaveAddress,
+ Command,
+ EfiSmbusReadByte,
+ FALSE,
+ &Length,
+ &Data
+ );
+
+ if (EFI_ERROR (Status) || ((Data & 0x0F) != CK505_GENERATOR_ID)) {
+ DEBUG((EFI_D_ERROR, "Clock Generator CK505 Not Present, vendor ID on board is %x\n",(Data & 0x0F)));
+ return EFI_SUCCESS;
+}
+ ClockGenID = Data & 0x0F;
+
+ EnableSpreadSpectrum = FALSE;
+ VariableSize = sizeof (SYSTEM_CONFIGURATION);
+ ZeroMem (&SystemConfiguration, sizeof (SYSTEM_CONFIGURATION));
+
+ Status = (*PeiServices)->LocatePpi (
+ (CONST EFI_PEI_SERVICES **) PeiServices,
+ &gEfiPeiReadOnlyVariable2PpiGuid,
+ 0,
+ NULL,
+ (VOID **) &Variable
+ );
+ //
+ // Use normal setup default from NVRAM variable,
+ // the Platform Mode (manufacturing/safe/normal) is handle in PeiGetVariable.
+ //
+ VariableSize = sizeof(SYSTEM_CONFIGURATION);
+ Status = Variable->GetVariable (Variable,
+ L"Setup",
+ &gEfiSetupVariableGuid,
+ NULL,
+ &VariableSize,
+ &SystemConfiguration);
+
+ if(!EFI_ERROR (Status)){
+ EnableSpreadSpectrum = SystemConfiguration.EnableClockSpreadSpec;
+ }
+
+ //
+ // Perform platform-specific intialization dependent upon Board ID:
+ //
+ DEBUG((EFI_D_ERROR, "board id is %x, platform id is %x\n",PlatformInfoHob->BoardId,PlatformInfoHob->PlatformFlavor));
+
+
+ switch (PlatformInfoHob->BoardId) {
+ case BOARD_ID_MINNOW2:
+ default:
+ switch(PlatformInfoHob->PlatformFlavor) {
+ case FlavorTablet:
+ ConfigurationTable = ConfigurationTable_Tablet;
+ Length = sizeof (ConfigurationTable_Tablet);
+ break;
+ case FlavorMobile:
+ ConfigurationTable = ConfigurationTable_Mobile;
+ Length = sizeof (ConfigurationTable_Mobile);
+ break;
+ case FlavorDesktop:
+ default:
+ ConfigurationTable = ConfigurationTable_Desktop;
+ Length = sizeof (ConfigurationTable_Desktop);
+ break;
+ }
+ break;
+ }
+
+ //
+ // Perform common clock initialization:
+ //
+ // Program Spread Spectrum function.
+ //
+ if (EnableSpreadSpectrum)
+ {
+ ConfigurationTable[mSupportedClockGeneratorTable[ClockType].SpreadSpectrumByteOffset] |= mSupportedClockGeneratorTable[ClockType].SpreadSpectrumBitOffset;
+ } else {
+ ConfigurationTable[mSupportedClockGeneratorTable[ClockType].SpreadSpectrumByteOffset] &= ~(mSupportedClockGeneratorTable[ClockType].SpreadSpectrumBitOffset);
+ }
+
+
+#if CLKGEN_EN
+ Status = ConfigureClockGenerator (PeiServices, SmbusPpi, ClockType, ClockAddress, Length, ConfigurationTable);
+ ASSERT_EFI_ERROR (Status);
+#endif // CLKGEN_EN
+ return EFI_SUCCESS;
+}
+
+static EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList[] = {
+ {
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+ &gEfiPeiSmbusPpiGuid,
+ ConfigurePlatformClocks
+ }
+};
+
+EFI_STATUS
+InstallPlatformClocksNotify (
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+
+ DEBUG ((EFI_D_INFO, "InstallPlatformClocksNotify()...\n"));
+
+ Status = (*PeiServices)->NotifyPpi(PeiServices, &mNotifyList[0]);
+ ASSERT_EFI_ERROR (Status);
+ return EFI_SUCCESS;
+
+}
+
+#ifndef __GNUC__
+#pragma optimize( "", on )
+#endif