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