/** @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; }