/** @file
This file contains routines for PEI GPIO Helpers Lib
Copyright (c) 2019 Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include
#include
#include
#include
#include
#include
#include
#include
#include
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;
}