/** @file
|
This file contains routines for PEI GPIO Helpers Lib
|
|
Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
**/
|
#include <Library/HobLib.h>
|
#include <Base.h>
|
#include <Uefi/UefiBaseType.h>
|
#include <Library/IoLib.h>
|
#include <Library/DebugLib.h>
|
#include <Library/BaseMemoryLib.h>
|
#include <Library/GpioNativeLib.h>
|
#include <Library/GpioPrivateLib.h>
|
#include <Library/GpioHelpersLib.h>
|
#include <Library/PeiServicesLib.h>
|
#include <Library/ConfigBlockLib.h>
|
#include <ConfigBlock/PchGeneralConfig.h>
|
#include <Ppi/SiPolicy.h>
|
|
extern EFI_GUID gGpioLibUnlockHobGuid;
|
|
//
|
// GPIO Lock HOB
|
// Stores information on GPIO pads that should be left unlocked
|
//
|
typedef struct {
|
//
|
// GPIO PadConfig unlock data
|
//
|
UINT32 PadConfig;
|
//
|
// GPIO Output unlock data
|
//
|
UINT32 OutputState;
|
} GPIO_UNLOCK_HOB_DATA;
|
|
/**
|
This procedure will get index of GPIO Unlock HOB structure for selected GroupIndex and DwNum.
|
|
@param[in] GroupIndex GPIO group index
|
@param[in] DwNum DWORD index for a group.
|
For group which has less then 32 pads per group DwNum must be 0.
|
|
@retval GpioUnlockHobIndex
|
**/
|
STATIC
|
UINT32
|
GpioUnlockDataIndex (
|
IN UINT32 GroupIndex,
|
IN UINT32 DwNum
|
)
|
{
|
UINT32 GpioUnlockDataIndex;
|
UINT32 Index;
|
|
GpioUnlockDataIndex = 0;
|
|
for (Index = 0; Index < GroupIndex; Index++) {
|
GpioUnlockDataIndex += GPIO_GET_DW_NUM (GpioGetPadPerGroup (GpioGetGroupFromGroupIndex (Index))) + 1;
|
}
|
|
GpioUnlockDataIndex += DwNum;
|
return GpioUnlockDataIndex;
|
}
|
|
/**
|
This procedure will create GPIO HOB for storing unlock data
|
|
@retval Pointer to GPIO Unlock data structure
|
**/
|
STATIC
|
GPIO_UNLOCK_HOB_DATA*
|
GpioCreateUnlockData (
|
VOID
|
)
|
{
|
VOID *HobData;
|
GPIO_GROUP Group;
|
GPIO_GROUP GroupMin;
|
GPIO_GROUP GroupMax;
|
UINT32 GpioUnlockDataRecords;
|
|
GroupMin = GpioGetLowestGroup ();
|
GroupMax = GpioGetHighestGroup ();
|
GpioUnlockDataRecords = 0;
|
|
for (Group = GroupMin; Group <= GroupMax; Group++) {
|
GpioUnlockDataRecords += GPIO_GET_DW_NUM (GpioGetPadPerGroup (Group)) + 1;
|
}
|
|
HobData = BuildGuidHob (&gGpioLibUnlockHobGuid, GpioUnlockDataRecords * sizeof (GPIO_UNLOCK_HOB_DATA));
|
if (HobData == NULL) {
|
return NULL;
|
}
|
|
ZeroMem (HobData, GpioUnlockDataRecords * sizeof (GPIO_UNLOCK_HOB_DATA));
|
|
return (GPIO_UNLOCK_HOB_DATA*)HobData;
|
}
|
|
/**
|
This procedure will Get GPIO Unlock data structure for storing unlock data.
|
If HOB doesn't exist it will be created.
|
|
@param[out] GpioUnlockData pointer to GPIO Unlock data structure
|
|
@retval Length number of GPIO unlock data records
|
**/
|
STATIC
|
UINT32
|
GpioGetUnlockData (
|
GPIO_UNLOCK_HOB_DATA **GpioUnlockData
|
)
|
{
|
VOID *Hob;
|
|
Hob = GetFirstGuidHob (&gGpioLibUnlockHobGuid);
|
if (Hob == NULL) {
|
//
|
// It is the first time this function is used so create the HOB
|
//
|
*GpioUnlockData = GpioCreateUnlockData ();
|
if (*GpioUnlockData == NULL) {
|
return 0;
|
}
|
Hob = GetFirstGuidHob (&gGpioLibUnlockHobGuid);
|
} else {
|
*GpioUnlockData = (GPIO_UNLOCK_HOB_DATA*) GET_GUID_HOB_DATA (Hob);
|
}
|
return GET_GUID_HOB_DATA_SIZE (Hob) / sizeof (GPIO_UNLOCK_HOB_DATA);
|
}
|
|
/**
|
This procedure will get pointer to GPIO Unlock data structure.
|
|
@param[out] GpioUnlockData pointer to GPIO Unlock data structure
|
|
@retval Length number of GPIO unlock data records
|
**/
|
STATIC
|
UINT32
|
GpioLocateUnlockData (
|
GPIO_UNLOCK_HOB_DATA **GpioUnlockData
|
)
|
{
|
VOID *Hob;
|
|
Hob = GetFirstGuidHob (&gGpioLibUnlockHobGuid);
|
if (Hob == NULL) {
|
*GpioUnlockData = NULL;
|
return 0;
|
}
|
|
*GpioUnlockData = (GPIO_UNLOCK_HOB_DATA*) GET_GUID_HOB_DATA (Hob);
|
return GET_GUID_HOB_DATA_SIZE (Hob) / sizeof (GPIO_UNLOCK_HOB_DATA);
|
}
|
|
/**
|
This procedure stores GPIO pad unlock information
|
|
@param[in] GpioPad GPIO pad
|
@param[in] GpioLockConfig GPIO Lock Configuration
|
|
@retval Status
|
**/
|
EFI_STATUS
|
GpioStoreUnlockData (
|
IN GPIO_PAD GpioPad,
|
IN GPIO_LOCK_CONFIG GpioLockConfig
|
)
|
{
|
GPIO_UNLOCK_HOB_DATA *GpioUnlockData;
|
UINT32 Length;
|
UINT32 GroupIndex;
|
UINT32 PadNumber;
|
UINT32 Index;
|
|
if (GpioLockConfig == GpioLockDefault) {
|
return EFI_SUCCESS;
|
}
|
|
Length = GpioGetUnlockData (&GpioUnlockData);
|
if (Length == 0) {
|
return EFI_NOT_FOUND;
|
}
|
|
GroupIndex = GpioGetGroupIndexFromGpioPad (GpioPad);
|
PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
|
Index = GpioUnlockDataIndex (GroupIndex, GPIO_GET_DW_NUM (PadNumber));
|
|
if (Index >= Length) {
|
return EFI_INVALID_PARAMETER;
|
}
|
|
if ((GpioLockConfig & B_GPIO_LOCK_CONFIG_PAD_CONF_LOCK_MASK) == GpioPadConfigUnlock) {
|
GpioUnlockData[Index].PadConfig |= 1 << (GpioGetPadNumberFromGpioPad (GpioPad) % 32);
|
}
|
|
if ((GpioLockConfig & B_GPIO_LOCK_CONFIG_OUTPUT_LOCK_MASK) == GpioOutputStateUnlock) {
|
GpioUnlockData[Index].OutputState |= 1 << (GpioGetPadNumberFromGpioPad (GpioPad) % 32);
|
}
|
|
return EFI_SUCCESS;
|
}
|
|
/**
|
This procedure stores GPIO group data about pads which PadConfig needs to be unlocked.
|
|
@param[in] GroupIndex GPIO group index
|
@param[in] DwNum DWORD index for a group.
|
For group which has less then 32 pads per group DwNum must be 0.
|
@param[in] UnlockedPads DWORD bitmask for pads which are going to be left unlocked
|
Bit position - PadNumber
|
Bit value - 0: Skip, 1: Leave unlocked
|
|
@retval Status
|
**/
|
EFI_STATUS
|
GpioStoreGroupDwUnlockPadConfigData (
|
IN UINT32 GroupIndex,
|
IN UINT32 DwNum,
|
IN UINT32 UnlockedPads
|
)
|
{
|
GPIO_UNLOCK_HOB_DATA *GpioUnlockData;
|
UINT32 Length;
|
UINT32 Index;
|
|
if (UnlockedPads == 0) {
|
//
|
// No pads to be left unlocked
|
//
|
return EFI_SUCCESS;
|
}
|
|
Length = GpioGetUnlockData (&GpioUnlockData);
|
if (Length == 0) {
|
return EFI_NOT_FOUND;
|
}
|
|
Index = GpioUnlockDataIndex (GroupIndex, DwNum);
|
if (Index >= Length) {
|
return EFI_INVALID_PARAMETER;
|
}
|
|
GpioUnlockData[Index].PadConfig |= UnlockedPads;
|
return EFI_SUCCESS;
|
}
|
|
/**
|
This procedure stores GPIO group data about pads which Output state needs to be unlocked.
|
|
@param[in] GroupIndex GPIO group index
|
@param[in] DwNum DWORD index for a group.
|
For group which has less then 32 pads per group DwNum must be 0.
|
@param[in] UnlockedPads DWORD bitmask for pads which are going to be left unlocked
|
Bit position - PadNumber
|
Bit value - 0: Skip, 1: Leave unlocked
|
@retval Status
|
**/
|
EFI_STATUS
|
GpioStoreGroupDwUnlockOutputData (
|
IN UINT32 GroupIndex,
|
IN UINT32 DwNum,
|
IN UINT32 UnlockedPads
|
)
|
{
|
GPIO_UNLOCK_HOB_DATA *GpioUnlockData;
|
UINT32 Length;
|
UINT32 Index;
|
|
if (UnlockedPads == 0) {
|
//
|
// No pads to be left unlocked
|
//
|
return EFI_SUCCESS;
|
}
|
|
Length = GpioGetUnlockData (&GpioUnlockData);
|
if (Length == 0) {
|
return EFI_NOT_FOUND;
|
}
|
|
Index = GpioUnlockDataIndex (GroupIndex, DwNum);
|
if (Index >= Length) {
|
return EFI_INVALID_PARAMETER;
|
}
|
|
GpioUnlockData[Index].OutputState |= UnlockedPads;
|
return EFI_SUCCESS;
|
}
|
|
/**
|
This procedure will get GPIO group data with pads, which PadConfig is supposed to be left unlock
|
|
@param[in] GroupIndex GPIO group index
|
@param[in] DwNum DWORD index for a group.
|
For group which has less then 32 pads per group DwNum must be 0.
|
@retval UnlockedPads DWORD bitmask for pads which are going to be left unlocked
|
Bit position - PadNumber
|
Bit value - 0: to be locked, 1: Leave unlocked
|
**/
|
UINT32
|
GpioGetGroupDwUnlockPadConfigMask (
|
IN UINT32 GroupIndex,
|
IN UINT32 DwNum
|
)
|
{
|
GPIO_UNLOCK_HOB_DATA *GpioUnlockData;
|
UINT32 Length;
|
UINT32 Index;
|
|
Length = GpioLocateUnlockData (&GpioUnlockData);
|
if (Length == 0) {
|
return 0;
|
}
|
|
Index = GpioUnlockDataIndex (GroupIndex, DwNum);
|
if (Index >= Length) {
|
return 0;
|
}
|
|
return GpioUnlockData[Index].PadConfig;
|
}
|
|
/**
|
This procedure will get GPIO group data with pads, which Output is supposed to be left unlock
|
|
@param[in] GroupIndex GPIO group index
|
@param[in] DwNum DWORD index for a group.
|
For group which has less then 32 pads per group DwNum must be 0.
|
@retval UnlockedPads DWORD bitmask for pads which are going to be left unlocked
|
Bit position - PadNumber
|
Bit value - 0: to be locked, 1: Leave unlocked
|
**/
|
UINT32
|
GpioGetGroupDwUnlockOutputMask (
|
IN UINT32 GroupIndex,
|
IN UINT32 DwNum
|
)
|
{
|
GPIO_UNLOCK_HOB_DATA *GpioUnlockData;
|
UINT32 Length;
|
UINT32 Index;
|
|
Length = GpioLocateUnlockData (&GpioUnlockData);
|
if (Length == 0) {
|
return 0;
|
}
|
|
Index = GpioUnlockDataIndex (GroupIndex, DwNum);
|
if (Index >= Length) {
|
return 0;
|
}
|
|
return GpioUnlockData[Index].OutputState;
|
}
|
|
/**
|
Obtains GpioOverride Information from PreMem config
|
|
@retval TRUE GPIO Override obtained successfully
|
FALSE Unable to obtain GPIO Override data
|
**/
|
BOOLEAN
|
STATIC
|
GetGpioOverrideFromConfigBlock (
|
IN OUT UINT8 *GpioOverride
|
)
|
{
|
EFI_STATUS Status;
|
SI_PREMEM_POLICY_PPI *SiPreMemPolicyPpi;
|
PCH_GENERAL_PREMEM_CONFIG *PchGeneralPreMemConfig;
|
|
Status = PeiServicesLocatePpi (
|
&gSiPreMemPolicyPpiGuid,
|
0,
|
NULL,
|
(VOID **) &SiPreMemPolicyPpi
|
);
|
if (EFI_ERROR (Status)) {
|
return FALSE;
|
}
|
Status = GetConfigBlock ((VOID *) SiPreMemPolicyPpi, &gPchGeneralPreMemConfigGuid, (VOID *) &PchGeneralPreMemConfig);
|
if (EFI_ERROR (Status)) {
|
return FALSE;
|
}
|
*GpioOverride = (UINT8) PchGeneralPreMemConfig->GpioOverride;
|
|
return TRUE;
|
}
|
|
/**
|
Returns Gpio Override Level1 Information
|
|
@retval TRUE/FALSE GPIO Override Level 1 Enabled/Disabled
|
**/
|
BOOLEAN
|
GpioOverrideLevel1Enabled (
|
VOID
|
)
|
{
|
UINT8 GpioOverride;
|
|
GpioOverride = 0;
|
|
if (GetGpioOverrideFromConfigBlock (&GpioOverride)) {
|
if (GpioOverride == 1) { return TRUE; }
|
}
|
|
return FALSE;
|
}
|