/** @file
Platform Clocks Lib file
@copyright
Copyright 1999 - 2021 Intel Corporation.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MAX_SMBUS_RETRIES 10
EFI_STATUS
ConfigureClockGeneratorOnSecondarySmbus (
IN EFI_PEI_SERVICES **PeiServices,
IN EFI_PEI_SMBUS2_PPI *SmbusPpi,
IN UINT8 ClockAddress,
IN UINTN ConfigurationTableLength,
IN BOOLEAN EnableSpreadSpectrum,
IN CLOCK_GENERATOR_DETAILS *mSupportedClockGeneratorT,
IN OUT UINT8 *ConfigurationTable
);
/**
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 CLOCK_GENERATOR_TYPE ClockType,
IN UINT8 ClockAddress,
IN UINTN ConfigurationTableLength,
IN OUT UINT8 *ConfigurationTable,
IN BOOLEAN EnableSpreadSpectrum,
IN CLOCK_GENERATOR_DETAILS *mSupportedClockGeneratorT,
IN UINT8 SecondarySmbus
)
{
EFI_STATUS Status;
EFI_SMBUS_DEVICE_ADDRESS SlaveAddress;
UINT8 Buffer[MAX_CLOCK_GENERATOR_BUFFER_LENGTH];
UINTN Length;
EFI_SMBUS_DEVICE_COMMAND Command;
EFI_PEI_SMBUS2_PPI *SmbusPpi;
UINT8 SmbErrorsCounter;
//
// Locate SmBus Ppi
//
Status = (**PeiServices).LocatePpi (
PeiServices,
&gEfiPeiSmbus2PpiGuid,
0,
NULL,
&SmbusPpi
);
ASSERT_EFI_ERROR (Status);
//
// Verify input arguments
//
ASSERT (ConfigurationTableLength >= 8);
ASSERT (ConfigurationTableLength <= MAX_CLOCK_GENERATOR_BUFFER_LENGTH);
ASSERT (ClockType < ClockGeneratorMax);
ASSERT (ConfigurationTable != NULL);
//
// Init some local vars
//
SlaveAddress.SmbusDeviceAddress = ClockAddress >> 1;
Length = sizeof (Buffer);
Command = 0;
if (SecondarySmbus == TRUE) {
return (ConfigureClockGeneratorOnSecondarySmbus(PeiServices,
SmbusPpi,
ClockAddress,
ConfigurationTableLength,
EnableSpreadSpectrum,
mSupportedClockGeneratorT,
ConfigurationTable
));
} else {
//
// Not LightningRidge
// Read the clock generator on the primary SMBus
//
SmbErrorsCounter = 0;
do
{
Status = SmbusPpi->Execute (
SmbusPpi,
SlaveAddress,
Command,
EfiSmbusReadBlock,
FALSE,
&Length,
Buffer
);
if(Status != EFI_SUCCESS)
{
DEBUG ((EFI_D_ERROR, "SMBUS reading error\n"));
}
SmbErrorsCounter ++;
}
while ((Status != EFI_SUCCESS) && (SmbErrorsCounter < MAX_SMBUS_RETRIES));
//
// Sanity check that the requested clock type is present in our supported clocks table
//
DEBUG ((DEBUG_INFO, "Expected Clock Generator ID is %x, populated %x\n", mSupportedClockGeneratorT->ClockId, Buffer[7]));
if (EnableSpreadSpectrum) {
Buffer[mSupportedClockGeneratorT->SpreadSpectrumByteOffset] |= mSupportedClockGeneratorT->SpreadSpectrumBitOffset;
if (ClockType == ClockGeneratorCk420) {
// Ensure that the clock chip is operating in normal mode.
//
Buffer[10] &= ~BIT7;
}
} else {
Buffer[mSupportedClockGeneratorT->SpreadSpectrumByteOffset] &= ~(mSupportedClockGeneratorT->SpreadSpectrumBitOffset);
}
#ifdef EFI_DEBUG
{
UINT8 i;
DEBUG ((DEBUG_INFO, "SlaveAddress.SmbusDeviceAddress %x: Size =%x\n", SlaveAddress.SmbusDeviceAddress, Length));
for (i = 0; i < ConfigurationTableLength; i++) {
DEBUG ((DEBUG_INFO, "Default Clock Generator Byte %d: %x\n", i, Buffer[i]));
}
}
#endif
//
// Program clock generator, using the platform default values
//
SmbErrorsCounter = 0;
do
{
Command = 0;
Status = SmbusPpi->Execute (
SmbusPpi,
SlaveAddress,
Command,
EfiSmbusWriteBlock,
FALSE,
&Length, // &ConfigurationTableLength,
Buffer //ConfigurationTable
);
// ASSERT_EFI_ERROR (Status);
if(Status != EFI_SUCCESS)
{
DEBUG ((EFI_D_ERROR, "SMBUS writing error\n"));
}
SmbErrorsCounter ++;
}
while ((Status != EFI_SUCCESS) && (SmbErrorsCounter < MAX_SMBUS_RETRIES));
//
// Dump contents after write
//
#ifdef EFI_DEBUG
{
UINT8 i;
SlaveAddress.SmbusDeviceAddress = ClockAddress >> 1;
Length = sizeof (Buffer);
Command = 0;
Status = SmbusPpi->Execute (
SmbusPpi,
SlaveAddress,
Command,
EfiSmbusReadBlock,
FALSE,
&Length,
Buffer
);
for (i = 0; i < ConfigurationTableLength; i++) {
DEBUG ((DEBUG_INFO, "Clock Generator Byte %d: %x\n", i, Buffer[i]));
}
}
#endif
return EFI_SUCCESS;
} // else ()
}
/**
Configure clock generator on Kahuna
Clock gen is on a secondary SMBus
@param IN EFI_PEI_SERVICES **PeiServices - Pointer to PEI Services table
@param IN EFI_PEI_SMBUS2_PPI *SmbusPpi - Pointer to SMBUs services PPI
@param IN UINT8 ClockAddress - SMBus address of clock gen
@param IN UINT8 *Buffer - Pointer to buffer containing byte stream to send to clock gen
@param IN UINTN Length - Number of bytes in buffer
@retval EFI_SUCCESS The function completed successfully.
@retval EFI_INVALID_PARAMETER The function cannot continue due to length is out of bound.
**/
EFI_STATUS
ConfigureClockGeneratorOnSecondarySmbus (
IN EFI_PEI_SERVICES **PeiServices,
IN EFI_PEI_SMBUS2_PPI *SmbusPpi,
IN UINT8 ClockAddress,
IN UINTN ConfigurationTableLength,
IN BOOLEAN EnableSpreadSpectrum,
IN CLOCK_GENERATOR_DETAILS *mSupportedClockGeneratorT,
IN OUT UINT8 *ConfigurationTable
)
{
EFI_PEI_STALL_PPI *StallPpi;
EFI_STATUS Status;
EFI_SMBUS_DEVICE_ADDRESS SlaveAddress;
EFI_SMBUS_DEVICE_COMMAND SmbusCommand;
UINTN SmbusLength;
UINT8 SmbusData[MAX_CLOCK_GENERATOR_BUFFER_LENGTH];
UINT8 Buffer[MAX_CLOCK_GENERATOR_BUFFER_LENGTH];
UINT8 Length;
ZeroMem (Buffer, sizeof(Buffer));
if (ConfigurationTableLength > MAX_CLOCK_GENERATOR_BUFFER_LENGTH) {
return EFI_INVALID_PARAMETER;
}
//
// Locate Stall PPI
//
Status = (**PeiServices).LocatePpi (
PeiServices,
&gEfiPeiStallPpiGuid,
0,
NULL,
&StallPpi
);
ASSERT_EFI_ERROR (Status);
//
// Get length of payload to send to clock gen
//
Length = (UINT8) ConfigurationTableLength;
//
// Copy the default clock generator data into Buffer
//
CopyMem ((VOID*)Buffer, ConfigurationTable, Length);
//
// Set spread spectrum bit in Buffer or clear it?
//
if (EnableSpreadSpectrum) {
Buffer[mSupportedClockGeneratorT->SpreadSpectrumByteOffset] |= mSupportedClockGeneratorT->SpreadSpectrumBitOffset;
if (mSupportedClockGeneratorT->ClockType == ClockGeneratorCk420) {
//
// Ensure that the clock chip is operating in normal mode.
//
Buffer[10] &= ~BIT7;
}
} else {
Buffer[mSupportedClockGeneratorT->SpreadSpectrumByteOffset] &= ~(mSupportedClockGeneratorT->SpreadSpectrumBitOffset);
}
//
// Now encapsulate the data for a Write Block command to the clock gen
// as the payload in a Write Block command to the SMBus bridge
//
// Segment address = 0xF2, this becomes slave address
// Slave address (clock gen) = ClockAddress, this becomes slave command
//
SlaveAddress.SmbusDeviceAddress = (0xF2 >> 1);
SmbusCommand = ClockAddress;
//
// Set byte index in clock gen to start with, always 0
//
SmbusData[0] = 0;
//
// Set byte count clock gen wants to see
//
SmbusData[1] = (UINT8) Length;
//
// Payload byte count for SMBus bridge
//
SmbusLength = Length + 2;
if (SmbusLength > MAX_CLOCK_GENERATOR_BUFFER_LENGTH) {
return EFI_INVALID_PARAMETER;
}
//
// Copy the clock gen data to the SMBus buffer
//
CopyMem ((VOID *)(((UINT8*)SmbusData) + 2), (VOID *)Buffer, Length);
//
// Use EfiSmbusWriteBlock to communicate with clock gen
//
Status = SmbusPpi->Execute( SmbusPpi,
SlaveAddress,
SmbusCommand,
EfiSmbusWriteBlock,
FALSE,
&SmbusLength,
&SmbusData );
return Status;
}