summaryrefslogtreecommitdiff
path: root/Silicon/Intel/LewisburgPkg/Library/PeiDxeSmmGpioLib/GpioLib.c
diff options
context:
space:
mode:
Diffstat (limited to 'Silicon/Intel/LewisburgPkg/Library/PeiDxeSmmGpioLib/GpioLib.c')
-rw-r--r--Silicon/Intel/LewisburgPkg/Library/PeiDxeSmmGpioLib/GpioLib.c2744
1 files changed, 2744 insertions, 0 deletions
diff --git a/Silicon/Intel/LewisburgPkg/Library/PeiDxeSmmGpioLib/GpioLib.c b/Silicon/Intel/LewisburgPkg/Library/PeiDxeSmmGpioLib/GpioLib.c
new file mode 100644
index 0000000000..0b82c2b8df
--- /dev/null
+++ b/Silicon/Intel/LewisburgPkg/Library/PeiDxeSmmGpioLib/GpioLib.c
@@ -0,0 +1,2744 @@
+/** @file
+
+Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "GpioLibrary.h"
+#include <Uefi/UefiMultiPhase.h>
+#include <Pi/PiMultiPhase.h>
+#include <Library/HobLib.h>
+
+//
+// Possible registers to be accessed using GpioReadWriteReg() function
+//
+typedef enum {
+ GpioHostOwnershipRegister = 0,
+ GpioGpeEnableRegister,
+ GpioSmiEnableRegister,
+ GpioNmiEnableRegister,
+ GpioPadConfigLockRegister,
+ GpioPadLockOutputRegister
+} GPIO_REG;
+
+/**
+ This procedure will write or read GPIO Pad Configuration register
+
+ @param[in] GpioPad GPIO pad
+ @param[in] DwReg Choose PADCFG register: 0:DW0, 1:DW1
+ @param[in] Mask Mask
+ @param[in] Write Perform read(0) or write(1)
+ @param[in,out] ReadWriteValue Read/Write data
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or pad number
+ @retval EFI_UNSUPPORTED Host cannot access this pad
+**/
+static
+EFI_STATUS
+GpioReadWritePadCfgReg (
+ IN GPIO_PAD GpioPad,
+ IN UINT8 DwReg,
+ IN UINT32 Mask,
+ IN BOOLEAN Write,
+ IN OUT UINT32 *ReadWriteVal
+ )
+{
+ UINT32 PadCfgReg;
+ GPIO_GROUP_INFO *GpioGroupInfo;
+ UINTN GpioGroupInfoLength;
+ UINT32 GroupIndex;
+ UINT32 PadNumber;
+
+
+ GPIO_PAD_OWN PadOwnVal;
+
+
+ GroupIndex = GpioGetGroupIndexFromGpioPad (GpioPad);
+ PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
+
+DEBUG_CODE_BEGIN();
+ if (!GpioIsCorrectPadForThisChipset (GpioPad)) {
+ DEBUG ((DEBUG_ERROR, "GPIO ERROR: Incorrect GpioPad define used on this chipset (Group=%d, Pad=%d)!\n", GroupIndex, PadNumber));
+ return EFI_UNSUPPORTED;
+ }
+DEBUG_CODE_END();
+
+ GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
+
+ //
+ // Check if group argument exceeds GPIO GROUP INFO array
+ //
+ if ((UINTN)GroupIndex >= GpioGroupInfoLength) {
+ DEBUG ((DEBUG_ERROR, "GPIO ERROR: Group argument (%d) exceeds GPIO group range\n", GroupIndex));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check if legal pin number
+ //
+ if (PadNumber >= GpioGroupInfo[GroupIndex].PadPerGroup) {
+ DEBUG ((DEBUG_ERROR, "GPIO ERROR: Pin number (%d) exceeds possible range for this group\n", PadNumber));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Write && (DwReg == 1 || (Mask & ~B_PCH_GPIO_TX_STATE) != 0) && GpioIsPadLocked (GroupIndex, PadNumber)) {
+ DEBUG ((DEBUG_ERROR, "GPIO ERROR: Pad is locked (Group=%d, Pad=%d)!\n", GroupIndex, PadNumber));
+ return EFI_WRITE_PROTECTED;
+ }
+
+DEBUG_CODE_BEGIN();
+ //
+ // Check if selected GPIO Pad is not owned by CSME/ISH
+ // If GPIO is not owned by Host all access to PadCfg will be dropped
+ //
+ GpioGetPadOwnership (GpioPad, &PadOwnVal);
+ if (PadOwnVal != GpioPadOwnHost) {
+ DEBUG ((DEBUG_ERROR, "GPIO ERROR: Accessing pad not owned by host (Group=%d, Pad=%d)!\n", GroupIndex, PadNumber));
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+DEBUG_CODE_END();
+
+ //
+ // Create Pad Configuration register offset
+ //
+ PadCfgReg = 0x8 * PadNumber + GpioGroupInfo[GroupIndex].PadCfgOffset;
+ if(DwReg == 1) {
+ PadCfgReg += 0x4;
+ }
+
+ if (Write) {
+ MmioAndThenOr32 (
+ (UINTN)PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, PadCfgReg),
+ (UINT32)(~Mask),
+ (UINT32)(*ReadWriteVal & Mask)
+ );
+ } else {
+ *ReadWriteVal = MmioRead32 (PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, PadCfgReg));
+ *ReadWriteVal &= Mask;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This procedure will write or read GPIO register
+
+ @param[in] RegType GPIO register type
+ @param[in] Group GPIO group
+ @param[in] DwNum Register number for current group (parameter applicable in accessing whole register).
+ For group which has less then 32 pads per group DwNum must be 0.
+ @param[in] GpioPad GPIO pad
+ @param[in] Write Perform read(0) or write(1)
+ @param[in] OnePad Access whole register(0) or one pad(1)
+ @param[in,out] ReadWriteValue Read/Write data
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group, pad or DwNum parameter number
+**/
+static
+EFI_STATUS
+GpioReadWriteReg (
+ IN GPIO_REG RegType,
+ IN GPIO_GROUP Group,
+ IN UINT32 DwNum,
+ IN GPIO_PAD GpioPad,
+ IN BOOLEAN Write,
+ IN BOOLEAN OnePad,
+ IN OUT UINT32 *ReadWriteVal
+ )
+{
+ UINT32 Mask;
+ UINT32 RegOffset;
+ UINT32 GroupIndex;
+ UINT32 PadNumber;
+ GPIO_GROUP_INFO *GpioGroupInfo;
+ UINTN GpioGroupInfoLength;
+
+ RegOffset = 0;
+ GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
+
+ if (OnePad) {
+ GroupIndex = GpioGetGroupIndexFromGpioPad (GpioPad);
+ PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
+DEBUG_CODE_BEGIN();
+ if (!GpioIsCorrectPadForThisChipset (GpioPad)) {
+ DEBUG ((DEBUG_ERROR, "GPIO ERROR: Incorrect GpioPad define used on this chipset (Group=%d, Pad=%d)!\n", GroupIndex, PadNumber));
+ return EFI_UNSUPPORTED;
+ }
+DEBUG_CODE_END();
+ } else {
+ GroupIndex = GpioGetGroupIndexFromGroup (Group);
+ PadNumber = 0;
+ }
+ //
+ // Check if group argument exceeds GPIO GROUP INFO array
+ //
+ if ((UINTN)GroupIndex >= GpioGroupInfoLength) {
+ DEBUG ((DEBUG_ERROR, "GPIO ERROR: Group argument (%d) exceeds GPIO group range\n", GroupIndex));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ switch (RegType) {
+ case GpioHostOwnershipRegister:
+ RegOffset = GpioGroupInfo[GroupIndex].HostOwnOffset;
+ break;
+ case GpioGpeEnableRegister:
+ RegOffset = GpioGroupInfo[GroupIndex].GpiGpeEnOffset;
+ break;
+ case GpioSmiEnableRegister:
+ RegOffset = GpioGroupInfo[GroupIndex].SmiEnOffset;
+ break;
+ case GpioNmiEnableRegister:
+ RegOffset = GpioGroupInfo[GroupIndex].NmiEnOffset;
+ break;
+ case GpioPadConfigLockRegister:
+ RegOffset = GpioGroupInfo[GroupIndex].PadCfgLockOffset;
+ break;
+ case GpioPadLockOutputRegister:
+ RegOffset = GpioGroupInfo[GroupIndex].PadCfgLockTxOffset;
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+
+ //
+ // Check if selected register exists
+ //
+ if (RegOffset == NO_REGISTER_FOR_PROPERTY) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Access one GPIO Pad
+ //
+ if (OnePad) {
+ //
+ // Check if legal pin number
+ //
+ if (PadNumber >= GpioGroupInfo[GroupIndex].PadPerGroup){
+ DEBUG ((DEBUG_ERROR, "GPIO ERROR: Pin number (%d) exceeds possible range for this group\n", PadNumber));
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // For future use. If there are more then 32 pads per group then certain
+ // group information would be split into more then one DWord register.
+ //
+ RegOffset += (PadNumber >> 5) * 0x4;
+ //
+ // Calculate pad bit position within DWord register
+ //
+ PadNumber %= 32;
+ Mask = BIT0 << PadNumber;
+
+ if (Write) {
+ MmioAndThenOr32 (
+ (UINTN)PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, RegOffset),
+ (UINT32)(~Mask),
+ (UINT32)((*ReadWriteVal << PadNumber) & Mask)
+ );
+ } else {
+ *ReadWriteVal = MmioRead32 (PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, RegOffset));
+ *ReadWriteVal = (*ReadWriteVal & Mask) >> PadNumber;
+ }
+ //
+ // Access whole register
+ //
+ } else {
+ //
+ // Check if DwNum argument does not exceed number of DWord registers
+ // resulting from available pads for certain group
+ //
+ if (DwNum > ((GpioGroupInfo[GroupIndex].PadPerGroup - 1) >> 5)){
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // For future use. If there are more then 32 pads per group then certain
+ // group information would be split into more then one DWord register.
+ // For SKL PCH DwNum must be 0.
+ //
+ RegOffset += DwNum *0x4;
+
+ if (Write) {
+ MmioWrite32 (
+ (UINTN)PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, RegOffset),
+ (UINT32)(*ReadWriteVal)
+ );
+ } else {
+ *ReadWriteVal = MmioRead32 (PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, RegOffset));
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This procedure will write GPIO Lock/LockTx register using SBI.
+
+ @param[in] RegType GPIO register (Lock or LockTx)
+ @param[in] Unlock Lock pads(0) or unlock(1)
+ @param[in] Group GPIO group number
+ @param[in] DwNum Register number for current group (parameter applicable in accessing whole register).
+ For group which has less then 32 pads per group DwNum must be 0.
+ @param[in] PadsToModify Bit mask for pads that are going to be modified
+ @param[in] GpioPad GPIO pad
+ @param[in] OnePad Access whole register(0) or one pad(1)
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group, pad or DwNum parameter number
+**/
+static
+EFI_STATUS
+GpioLockPadsUsingSbi (
+ IN GPIO_REG RegType,
+ IN BOOLEAN Unlock,
+ IN GPIO_GROUP Group,
+ IN UINT32 DwNum,
+ IN UINT32 PadsToModify,
+ IN GPIO_PAD GpioPad,
+ IN BOOLEAN OnePad
+ )
+{
+ UINT8 Response;
+ EFI_STATUS Status;
+ GPIO_GROUP_INFO *GpioGroupInfo;
+ UINTN GpioGroupInfoLength;
+ UINT32 RegOffset;
+ UINT32 OldPadCfgLockRegVal;
+ UINT32 NewPadCfgLockRegVal;
+ UINT32 GroupIndex;
+ UINT32 PadNumber;
+
+ RegOffset = 0;
+ OldPadCfgLockRegVal = 0;
+ GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
+
+ if (OnePad) {
+ GroupIndex = GpioGetGroupIndexFromGpioPad (GpioPad);
+ PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
+ Group = GpioGetGroupFromGpioPad (GpioPad);
+DEBUG_CODE_BEGIN();
+ if (!GpioIsCorrectPadForThisChipset (GpioPad)) {
+ DEBUG ((DEBUG_ERROR, "GPIO ERROR: Incorrect GpioPad define used on this chipset (Group=%d, Pad=%d)!\n", GroupIndex, PadNumber));
+ return EFI_UNSUPPORTED;
+ }
+DEBUG_CODE_END();
+ } else {
+ GroupIndex = GpioGetGroupIndexFromGroup (Group);
+ PadNumber = 0;
+ }
+
+ //
+ // Check if group argument exceeds GPIO GROUP INFO array
+ //
+ if ((UINTN)GroupIndex >= GpioGroupInfoLength) {
+ DEBUG ((DEBUG_ERROR, "GPIO ERROR: Group argument (%d) exceeds GPIO group range\n", GroupIndex));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ switch (RegType) {
+ case GpioPadConfigLockRegister:
+ RegOffset = GpioGroupInfo[GroupIndex].PadCfgLockOffset;
+ break;
+ case GpioPadLockOutputRegister:
+ RegOffset = GpioGroupInfo[GroupIndex].PadCfgLockTxOffset;
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+
+ //
+ // Check if selected register exists
+ //
+ if (RegOffset == NO_REGISTER_FOR_PROPERTY) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Access one GPIO Pad
+ //
+ if (OnePad) {
+ //
+ // Check if legal pin number
+ //
+ if (PadNumber >= GpioGroupInfo[GroupIndex].PadPerGroup){
+ DEBUG ((DEBUG_ERROR, "GPIO ERROR: Pin number (%d) exceeds possible range for this group\n", PadNumber));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // For future use. If there are more then 32 pads per group then certain
+ // group information would be split into more then one DWord register.
+ //
+ DwNum = (PadNumber >> 5);
+ RegOffset += DwNum * 0x4;
+ //
+ // Calculate pad bit position within DWord register
+ //
+ PadNumber %= 32;
+
+ switch (RegType) {
+ case GpioPadConfigLockRegister:
+ GpioGetPadCfgLockForGroupDw (Group, DwNum, &OldPadCfgLockRegVal);
+ break;
+ case GpioPadLockOutputRegister:
+ GpioGetPadCfgLockTxForGroupDw (Group, DwNum, &OldPadCfgLockRegVal);
+ break;
+ }
+ if (Unlock) {
+ NewPadCfgLockRegVal = OldPadCfgLockRegVal & (~(0x1 << PadNumber));
+ } else {
+ NewPadCfgLockRegVal = OldPadCfgLockRegVal | (0x1 << PadNumber);
+ }
+
+ } else {
+ //
+ // Access whole register
+ //
+
+ //
+ // Check if DwNum argument does not exceed number of DWord registers
+ // resulting from available pads for certain group
+ //
+ if (DwNum > ((GpioGroupInfo[GroupIndex].PadPerGroup - 1) >> 5)){
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // For future use. If there are more then 32 pads per group then certain
+ // group information would be split into more then one DWord register.
+ // For SKL PCH DwNum must be 0.
+ //
+ RegOffset += DwNum *0x4;
+
+ switch (RegType) {
+ case GpioPadConfigLockRegister:
+ GpioGetPadCfgLockForGroupDw (Group, DwNum, &OldPadCfgLockRegVal);
+ break;
+ case GpioPadLockOutputRegister:
+ GpioGetPadCfgLockTxForGroupDw (Group, DwNum, &OldPadCfgLockRegVal);
+ break;
+ }
+ if (Unlock) {
+ NewPadCfgLockRegVal = OldPadCfgLockRegVal & (~PadsToModify);
+ } else {
+ NewPadCfgLockRegVal = OldPadCfgLockRegVal | PadsToModify;
+ }
+ }
+
+ Status = PchSbiExecution (
+ GpioGroupInfo[GroupIndex].Community,
+ RegOffset,
+ GpioLockUnlock,
+ FALSE,
+ &NewPadCfgLockRegVal,
+ &Response
+ );
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
+
+/**
+ This procedure will read multiple GPIO settings
+
+ @param[in] GpioPad GPIO Pad
+ @param[out] GpioData GPIO data structure
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or pad number
+**/
+EFI_STATUS
+GpioGetPadConfig (
+ IN GPIO_PAD GpioPad,
+ OUT GPIO_CONFIG *GpioData
+ )
+{
+ UINT32 Dw0Reg;
+ UINT32 Dw1Reg;
+ UINT32 PadCfgReg;
+ UINT32 RegVal;
+ GPIO_GROUP_INFO *GpioGroupInfo;
+ UINTN GpioGroupInfoLength;
+ GPIO_GROUP Group;
+ UINT32 GroupIndex;
+ UINT32 PadNumber;
+
+ GPIO_PAD_OWN PadOwnVal;
+
+
+ GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
+
+ Group = GpioGetGroupFromGpioPad (GpioPad);
+ GroupIndex = GpioGetGroupIndexFromGpioPad (GpioPad);
+ PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
+
+DEBUG_CODE_BEGIN();
+ if (!GpioIsCorrectPadForThisChipset (GpioPad)) {
+ DEBUG ((DEBUG_ERROR, "GPIO ERROR: Incorrect GpioPad define used on this chipset (Group=%d, Pad=%d)!\n", GroupIndex, PadNumber));
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+
+ GpioGetPadOwnership (GpioPad, &PadOwnVal);
+ if (PadOwnVal != GpioPadOwnHost) {
+ DEBUG ((DEBUG_ERROR, "GPIO ERROR: Accessing pad not owned by host (Group=%d, Pad=%d)!\n", GroupIndex, PadNumber));
+ return EFI_UNSUPPORTED;
+ }
+DEBUG_CODE_END();
+
+ //
+ // Check if group argument exceeds GPIO group range
+ //
+ if ((Group < GpioGetLowestGroup ()) || (Group > GpioGetHighestGroup ())) {
+ DEBUG ((DEBUG_ERROR, "GPIO ERROR: Group argument (%d) exceeds GPIO group range\n", GroupIndex));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check if legal pin number
+ //
+ if (PadNumber >= GpioGroupInfo[GroupIndex].PadPerGroup){
+ DEBUG ((DEBUG_ERROR, "GPIO ERROR: Pin number (%d) exceeds possible range for this group\n", PadNumber));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Create PADCFG register offset using group and pad number
+ //
+ PadCfgReg = 0x8 * PadNumber + GpioGroupInfo[GroupIndex].PadCfgOffset;
+
+ //
+ // Read PADCFG DW0 register
+ //
+ Dw0Reg = MmioRead32 ((UINTN)PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, PadCfgReg));
+
+ //
+ // Read PADCFG DW1 register
+ //
+ Dw1Reg = MmioRead32 ((UINTN)PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, PadCfgReg + 0x4));
+
+
+ //
+ // Get Reset Type (PadRstCfg)
+ //
+ GpioData->PowerConfig = ((Dw0Reg & B_PCH_GPIO_RST_CONF) >> (N_PCH_GPIO_RST_CONF - (GPIO_CONF_RESET_BIT_POS + 1))) | (0x1 << GPIO_CONF_RESET_BIT_POS);
+
+ //
+ // Get how interrupt is triggered (RxEvCfg)
+ //
+ GpioData->InterruptConfig = ((Dw0Reg & B_PCH_GPIO_RX_LVL_EDG) >> (N_PCH_GPIO_RX_LVL_EDG - (GPIO_CONF_INT_TRIG_BIT_POS + 1))) | (0x1 << GPIO_CONF_INT_TRIG_BIT_POS);
+
+ //
+ // Get interrupt generation (GPIRoutIOxAPIC/SCI/SMI/NMI)
+ //
+ GpioData->InterruptConfig |= ((Dw0Reg & (B_PCH_GPIO_RX_NMI_ROUTE | B_PCH_GPIO_RX_SCI_ROUTE | B_PCH_GPIO_RX_SMI_ROUTE | B_PCH_GPIO_RX_APIC_ROUTE)) >> (N_PCH_GPIO_RX_NMI_ROUTE - (GPIO_CONF_INT_ROUTE_BIT_POS + 1))) | (0x1 << GPIO_CONF_INT_ROUTE_BIT_POS);
+
+ //
+ // Get GPIO direction (GPIORxDis and GPIOTxDis)
+ //
+ GpioData->Direction = ((Dw0Reg & (B_PCH_GPIO_RXDIS | B_PCH_GPIO_TXDIS)) >> (N_PCH_GPIO_TXDIS - (GPIO_CONF_DIR_BIT_POS + 1))) | (0x1 << GPIO_CONF_DIR_BIT_POS);
+
+ //
+ // Get GPIO input inversion (RXINV)
+ //
+ GpioData->Direction |= ((Dw0Reg & B_PCH_GPIO_RXINV) >> (N_PCH_GPIO_RXINV - (GPIO_CONF_INV_BIT_POS + 1))) | (0x1 << GPIO_CONF_INV_BIT_POS);
+
+ //
+ // Get GPIO output state (GPIOTxState)
+ //
+ GpioData->OutputState = ((Dw0Reg & B_PCH_GPIO_TX_STATE) << (N_PCH_GPIO_TX_STATE + (GPIO_CONF_OUTPUT_BIT_POS + 1))) | (0x1 << GPIO_CONF_OUTPUT_BIT_POS) ;
+
+ //
+ // Configure GPIO RX raw override to '1' (RXRAW1)
+ //
+ GpioData->OtherSettings = ((Dw0Reg & B_PCH_GPIO_RX_RAW1) >> (N_PCH_GPIO_RX_RAW1 - (GPIO_CONF_RXRAW_BIT_POS + 1))) | (0x1 << GPIO_CONF_RXRAW_BIT_POS) ;
+
+ //
+ // Get GPIO Pad Mode (PMode)
+ //
+ GpioData->PadMode = ((Dw0Reg & B_PCH_GPIO_PAD_MODE) >> (N_PCH_GPIO_PAD_MODE - (GPIO_CONF_PAD_MODE_BIT_POS + 1))) | (0x1 << GPIO_CONF_PAD_MODE_BIT_POS);
+
+ //
+ // Get GPIO termination (Term)
+ //
+ GpioData->ElectricalConfig = ((Dw1Reg & B_PCH_GPIO_TERM) >> (N_PCH_GPIO_TERM - (GPIO_CONF_TERM_BIT_POS + 1))) | (0x1 << GPIO_CONF_TERM_BIT_POS) ;
+
+ //
+ // Get GPIO pad tolerance (padtol)
+ //
+ GpioData->ElectricalConfig |= ((Dw1Reg & B_PCH_GPIO_PADTOL) >> (N_PCH_GPIO_PADTOL - (GPIO_CONF_PADTOL_BIT_POS + 1))) | (0x1 << GPIO_CONF_PADTOL_BIT_POS) ;
+
+ //
+ // Read HOSTSW_OWN registers
+ //
+ RegVal = MmioRead32 ((UINTN)PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, GpioGroupInfo[GroupIndex].HostOwnOffset));
+
+ //
+ // Get Host Software Ownership
+ //
+ GpioData->HostSoftPadOwn = (((RegVal >> PadNumber) & 0x1) << (GPIO_CONF_HOST_OWN_BIT_POS + 1)) | (0x1 << GPIO_CONF_HOST_OWN_BIT_POS);
+
+ //
+ // Read PADCFGLOCK register
+ //
+ RegVal = MmioRead32 ((UINTN)PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, GpioGroupInfo[GroupIndex].PadCfgLockOffset));
+
+ //
+ // Get Pad Configuration Lock state
+ //
+ GpioData->LockConfig = (((RegVal >> PadNumber) & 0x1) << 1) | 0x1;
+
+ //
+ // Read PADCFGLOCKTX register
+ //
+ RegVal = MmioRead32 ((UINTN)PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, GpioGroupInfo[GroupIndex].PadCfgLockTxOffset));
+
+ //
+ // Get Pad Configuration Lock Tx state
+ //
+ GpioData->LockConfig |= (((RegVal >> PadNumber) & 0x1) << 2) | 0x1;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This procedure will configure multiple GPIO settings
+
+ @param[in] GpioPad GPIO Pad
+ @param[in] GpioData GPIO data structure
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or pad number
+**/
+EFI_STATUS
+GpioSetPadConfig (
+ IN GPIO_PAD GpioPad,
+ IN GPIO_CONFIG *GpioData
+ )
+{
+ UINT32 Dw0Reg;
+ UINT32 Dw0RegMask;
+ UINT32 Dw1Reg;
+ UINT32 Dw1RegMask;
+ UINT32 PadCfgReg;
+ UINT32 HostSoftOwnReg;
+ UINT32 HostSoftOwnRegMask;
+ UINT32 GpiGpeEnReg;
+ UINT32 GpiGpeEnRegMask;
+ GPIO_GROUP_INFO *GpioGroupInfo;
+ UINTN GpioGroupInfoLength;
+ GPIO_GROUP Group;
+ UINT32 GroupIndex;
+ UINT32 PadNumber;
+
+ GPIO_PAD_OWN PadOwnVal;
+
+
+ GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
+
+ Dw0RegMask = 0;
+ Dw0Reg = 0;
+ Dw1RegMask = 0;
+ Dw1Reg = 0;
+
+ Group = GpioGetGroupFromGpioPad (GpioPad);
+ GroupIndex = GpioGetGroupIndexFromGpioPad (GpioPad);
+ PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
+
+DEBUG_CODE_BEGIN();
+ if (!GpioIsCorrectPadForThisChipset (GpioPad)) {
+ DEBUG ((DEBUG_ERROR, "GPIO ERROR: Incorrect GpioPad define used on this chipset (Group=%d, Pad=%d)!\n", GroupIndex, PadNumber));
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+
+ GpioGetPadOwnership (GpioPad, &PadOwnVal);
+ if (PadOwnVal != GpioPadOwnHost) {
+ DEBUG ((DEBUG_ERROR, "GPIO ERROR: Accessing pad not owned by host (Group=%d, Pad=%d)!\n", GroupIndex, PadNumber));
+ return EFI_UNSUPPORTED;
+ }
+DEBUG_CODE_END();
+ //
+ // Check if group argument exceeds GPIO group range
+ //
+ if ((Group < GpioGetLowestGroup ()) || (Group > GpioGetHighestGroup ())) {
+ DEBUG ((DEBUG_ERROR, "GPIO ERROR: Group argument (%d) exceeds GPIO group range\n", GroupIndex));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check if legal pin number
+ //
+ if (PadNumber >= GpioGroupInfo[GroupIndex].PadPerGroup) {
+ DEBUG ((DEBUG_ERROR, "GPIO ERROR: Pin number (%d) exceeds possible range for this group\n", PadNumber));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (GpioIsPadLocked (GroupIndex, PadNumber)) {
+ DEBUG ((DEBUG_ERROR, "GPIO ERROR: Pad is locked (Group=%d, Pad=%d)!\n", GroupIndex, PadNumber));
+ return EFI_WRITE_PROTECTED;
+ }
+
+ //
+ // Configure Reset Type (PadRstCfg)
+ //
+ Dw0RegMask |= ((((GpioData->PowerConfig & GPIO_CONF_RESET_MASK) >> GPIO_CONF_RESET_BIT_POS) == GpioHardwareDefault) ? 0x0 : B_PCH_GPIO_RST_CONF);
+ Dw0Reg |= (((GpioData->PowerConfig & GPIO_CONF_RESET_MASK) >> (GPIO_CONF_RESET_BIT_POS + 1)) << N_PCH_GPIO_RST_CONF);
+
+ //
+ // Configure how interrupt is triggered (RxEvCfg)
+ //
+ Dw0RegMask |= ((((GpioData->InterruptConfig & GPIO_CONF_INT_TRIG_MASK) >> GPIO_CONF_INT_TRIG_BIT_POS) == GpioHardwareDefault) ? 0x0 : B_PCH_GPIO_RX_LVL_EDG);
+ Dw0Reg |= (((GpioData->InterruptConfig & GPIO_CONF_INT_TRIG_MASK) >> (GPIO_CONF_INT_TRIG_BIT_POS + 1)) << N_PCH_GPIO_RX_LVL_EDG);
+
+ //
+ // Configure interrupt generation (GPIRoutIOxAPIC/SCI/SMI/NMI)
+ //
+ Dw0RegMask |= ((((GpioData->InterruptConfig & GPIO_CONF_INT_ROUTE_MASK) >> GPIO_CONF_INT_ROUTE_BIT_POS) == GpioHardwareDefault) ? 0x0 : (B_PCH_GPIO_RX_NMI_ROUTE | B_PCH_GPIO_RX_SCI_ROUTE | B_PCH_GPIO_RX_SMI_ROUTE | B_PCH_GPIO_RX_APIC_ROUTE));
+ Dw0Reg |= (((GpioData->InterruptConfig & GPIO_CONF_INT_ROUTE_MASK) >> (GPIO_CONF_INT_ROUTE_BIT_POS + 1)) << N_PCH_GPIO_RX_NMI_ROUTE);
+
+ //
+ // Configure GPIO direction (GPIORxDis and GPIOTxDis)
+ //
+ Dw0RegMask |= ((((GpioData->Direction & GPIO_CONF_DIR_MASK) >> GPIO_CONF_DIR_BIT_POS) == GpioHardwareDefault) ? 0x0 : (B_PCH_GPIO_RXDIS | B_PCH_GPIO_TXDIS));
+ Dw0Reg |= (((GpioData->Direction & GPIO_CONF_DIR_MASK) >> (GPIO_CONF_DIR_BIT_POS + 1)) << N_PCH_GPIO_TXDIS);
+
+ //
+ // Configure GPIO input inversion (RXINV)
+ //
+ Dw0RegMask |= ((((GpioData->Direction & GPIO_CONF_INV_MASK) >> GPIO_CONF_INV_BIT_POS) == GpioHardwareDefault) ? 0x0 : B_PCH_GPIO_RXINV);
+ Dw0Reg |= (((GpioData->Direction & GPIO_CONF_INV_MASK) >> (GPIO_CONF_INV_BIT_POS + 1)) << N_PCH_GPIO_RXINV);
+
+ //
+ // Configure GPIO output state (GPIOTxState)
+ //
+ Dw0RegMask |= ((((GpioData->OutputState & GPIO_CONF_OUTPUT_MASK) >> GPIO_CONF_OUTPUT_BIT_POS) == GpioHardwareDefault) ? 0x0 : B_PCH_GPIO_TX_STATE);
+ Dw0Reg |= (((GpioData->OutputState & GPIO_CONF_OUTPUT_MASK) >> (GPIO_CONF_OUTPUT_BIT_POS + 1)) << N_PCH_GPIO_TX_STATE);
+
+ //
+ // Configure GPIO RX raw override to '1' (RXRAW1)
+ //
+ Dw0RegMask |= ((((GpioData->OtherSettings & GPIO_CONF_RXRAW_MASK) >> GPIO_CONF_RXRAW_BIT_POS) == GpioHardwareDefault) ? 0x0 : B_PCH_GPIO_RX_RAW1);
+ Dw0Reg |= (((GpioData->OtherSettings & GPIO_CONF_RXRAW_MASK) >> (GPIO_CONF_RXRAW_BIT_POS + 1)) << N_PCH_GPIO_RX_RAW1);
+
+ //
+ // Configure GPIO Pad Mode (PMode)
+ //
+ Dw0RegMask |= ((((GpioData->PadMode & GPIO_CONF_PAD_MODE_MASK) >> GPIO_CONF_PAD_MODE_BIT_POS) == GpioHardwareDefault) ? 0x0 : B_PCH_GPIO_PAD_MODE);
+ Dw0Reg |= (((GpioData->PadMode & GPIO_CONF_PAD_MODE_MASK) >> (GPIO_CONF_PAD_MODE_BIT_POS + 1)) << N_PCH_GPIO_PAD_MODE);
+
+ //
+ // Configure GPIO termination (Term)
+ //
+ Dw1RegMask |= ((((GpioData->ElectricalConfig & GPIO_CONF_TERM_MASK) >> GPIO_CONF_TERM_BIT_POS) == GpioHardwareDefault) ? 0x0 : B_PCH_GPIO_TERM);
+ Dw1Reg |= (((GpioData->ElectricalConfig & GPIO_CONF_TERM_MASK) >> (GPIO_CONF_TERM_BIT_POS + 1)) << N_PCH_GPIO_TERM);
+
+ //
+ // Configure GPIO pad tolerance (padtol)
+ //
+ Dw1RegMask |= ((((GpioData->ElectricalConfig & GPIO_CONF_PADTOL_MASK) >> GPIO_CONF_PADTOL_BIT_POS) == GpioHardwareDefault) ? 0x0 : B_PCH_GPIO_PADTOL);
+ Dw1Reg |= (((GpioData->ElectricalConfig & GPIO_CONF_PADTOL_MASK) >> (GPIO_CONF_PADTOL_BIT_POS + 1)) << N_PCH_GPIO_PADTOL);
+
+ //
+ // Create PADCFG register offset using group and pad number
+ //
+ PadCfgReg = 0x8 * PadNumber + GpioGroupInfo[GroupIndex].PadCfgOffset;
+
+ //
+ // Write PADCFG DW0 register
+ //
+ MmioAndThenOr32 (
+ (UINTN)PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, PadCfgReg),
+ ~(UINT32)Dw0RegMask,
+ (UINT32)Dw0Reg
+ );
+
+ //
+ // Write PADCFG DW1 register
+ //
+ MmioAndThenOr32 (
+ (UINTN)PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, PadCfgReg + 0x4),
+ ~(UINT32)Dw1RegMask,
+ (UINT32)Dw1Reg
+ );
+
+ //
+ // Update value to be programmed in HOSTSW_OWN register
+ //
+ HostSoftOwnRegMask = (GpioData->HostSoftPadOwn & 0x1) << PadNumber;
+ HostSoftOwnReg = (GpioData->HostSoftPadOwn >> 0x1) << PadNumber;
+
+ //
+ // Write HOSTSW_OWN registers
+ //
+ MmioAndThenOr32 (
+ (UINTN)PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, GpioGroupInfo[GroupIndex].HostOwnOffset),
+ ~(UINT32)HostSoftOwnRegMask,
+ (UINT32)HostSoftOwnReg
+ );
+
+ //
+ // Update value to be programmed in GPI_GPE_EN register
+ //
+ GpiGpeEnRegMask = (GpioData->InterruptConfig & 0x1) << PadNumber;
+ GpiGpeEnReg = ((GpioData->InterruptConfig & GpioIntSci) >> 3) << PadNumber;
+
+ //
+ // Write GPI_GPE_EN registers
+ //
+ MmioAndThenOr32 (
+ (UINTN)PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, GpioGroupInfo[GroupIndex].GpiGpeEnOffset),
+ ~(UINT32)GpiGpeEnRegMask,
+ (UINT32)GpiGpeEnReg
+ );
+
+ //
+ // Program Pad Configuration Lock
+ //
+ if ((GpioData->LockConfig & GpioPadConfigLock) == GpioPadConfigLock) {
+ GpioLockPadsUsingSbi (
+ GpioPadConfigLockRegister,
+ FALSE,
+ 0,
+ 0,
+ 0,
+ GpioPad,
+ TRUE
+ );
+ }
+
+ //
+ // Program Pad Configuration Lock Tx
+ //
+ if ((GpioData->LockConfig & GpioOutputStateLock) == GpioOutputStateLock) {
+ GpioLockPadsUsingSbi (
+ GpioPadLockOutputRegister,
+ FALSE,
+ 0,
+ 0,
+ 0,
+ GpioPad,
+ TRUE
+ );
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ This procedure will set GPIO output level
+
+ @param[in] GpioPad GPIO pad
+ @param[in] Value Output value
+ 0: OutputLow, 1: OutputHigh
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or pad number
+**/
+EFI_STATUS
+GpioSetOutputValue (
+ IN GPIO_PAD GpioPad,
+ IN UINT32 Value
+ )
+{
+ EFI_STATUS Status;
+
+ Status = GpioReadWritePadCfgReg (
+ GpioPad,
+ 0,
+ B_PCH_GPIO_TX_STATE,
+ TRUE,
+ &Value
+ );
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
+
+/**
+ This procedure will get GPIO output level
+
+ @param[in] GpioPad GPIO pad
+ @param[out] OutputVal GPIO Output value
+ 0: OutputLow, 1: OutputHigh
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or pad number
+**/
+EFI_STATUS
+GpioGetOutputValue (
+ IN GPIO_PAD GpioPad,
+ OUT UINT32 *OutputVal
+ )
+{
+ EFI_STATUS Status;
+
+ Status = GpioReadWritePadCfgReg (
+ GpioPad,
+ 0,
+ B_PCH_GPIO_TX_STATE,
+ FALSE,
+ OutputVal
+ );
+ ASSERT_EFI_ERROR (Status);
+ *OutputVal >>= N_PCH_GPIO_TX_STATE;
+
+ return Status;
+}
+
+/**
+ This procedure will get GPIO input level
+
+ @param[in] GpioPad GPIO pad
+ @param[out] InputVal GPIO Input value
+ 0: InputLow, 1: InpuHigh
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or pad number
+**/
+EFI_STATUS
+GpioGetInputValue (
+ IN GPIO_PAD GpioPad,
+ OUT UINT32 *InputVal
+ )
+{
+ EFI_STATUS Status;
+
+ Status = GpioReadWritePadCfgReg (
+ GpioPad,
+ 0,
+ B_PCH_GPIO_RX_STATE,
+ FALSE,
+ InputVal
+ );
+ ASSERT_EFI_ERROR (Status);
+ *InputVal >>= N_PCH_GPIO_RX_STATE;
+
+ return Status;
+}
+
+/**
+ This procedure will get GPIO IOxAPIC interrupt number
+
+ @param[in] GpioPad GPIO pad
+ @param[out] IrqNum IRQ number
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or pad number
+**/
+EFI_STATUS
+GpioGetPadIoApicIrqNumber (
+ IN GPIO_PAD GpioPad,
+ OUT UINT32 *IrqNum
+ )
+{
+ EFI_STATUS Status;
+
+ Status = GpioReadWritePadCfgReg (
+ GpioPad,
+ 1,
+ B_PCH_GPIO_INTSEL,
+ FALSE,
+ IrqNum
+ );
+ ASSERT_EFI_ERROR (Status);
+ *IrqNum >>= N_PCH_GPIO_INTSEL;
+
+ return Status;
+}
+
+/**
+ This procedure will configure GPIO input inversion
+
+ @param[in] GpioPad GPIO pad
+ @param[in] Value Value for GPIO input inversion
+ 0: No input inversion, 1: Invert input
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or pad number
+**/
+EFI_STATUS
+GpioSetInputInversion (
+ IN GPIO_PAD GpioPad,
+ IN UINT32 Value
+ )
+{
+ EFI_STATUS Status;
+
+ Value <<= N_PCH_GPIO_RXINV;
+ Status = GpioReadWritePadCfgReg (
+ GpioPad,
+ 0,
+ B_PCH_GPIO_RXINV,
+ TRUE,
+ &Value
+ );
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
+
+/**
+ This procedure will get GPIO pad input inversion value
+
+ @param[in] GpioPad GPIO pad
+ @param[out] InvertState GPIO inversion state
+ 0: No input inversion, 1: Inverted input
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or pad number
+**/
+EFI_STATUS
+GpioGetInputInversion (
+ IN GPIO_PAD GpioPad,
+ OUT UINT32 *InvertState
+ )
+{
+ EFI_STATUS Status;
+
+ Status = GpioReadWritePadCfgReg (
+ GpioPad,
+ 0,
+ B_PCH_GPIO_RXINV,
+ FALSE,
+ InvertState
+ );
+ ASSERT_EFI_ERROR (Status);
+ *InvertState >>= N_PCH_GPIO_RXINV;
+
+ return Status;
+}
+
+/**
+ This procedure will set GPIO interrupt settings
+
+ @param[in] GpioPad GPIO pad
+ @param[in] Value Value of Level/Edge
+ use GPIO_INT_CONFIG as argument
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or pad number
+**/
+EFI_STATUS
+GpioSetPadInterruptConfig (
+ IN GPIO_PAD GpioPad,
+ IN GPIO_INT_CONFIG Value
+ )
+{
+ EFI_STATUS Status;
+ UINT32 RxLvlEdgeValue;
+ UINT32 IntRouteValue;
+ UINT32 GpeEnable;
+
+ Status = EFI_SUCCESS;
+
+ if (((Value & GPIO_CONF_INT_TRIG_MASK) >> GPIO_CONF_INT_TRIG_BIT_POS) != GpioHardwareDefault) {
+ RxLvlEdgeValue = ((Value & GPIO_CONF_INT_TRIG_MASK) >> (GPIO_CONF_INT_TRIG_BIT_POS + 1)) << N_PCH_GPIO_RX_LVL_EDG;
+
+ Status = GpioReadWritePadCfgReg (
+ GpioPad,
+ 0,
+ B_PCH_GPIO_RX_LVL_EDG,
+ TRUE,
+ &RxLvlEdgeValue
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ if (((Value & GPIO_CONF_INT_ROUTE_MASK) >> GPIO_CONF_INT_ROUTE_BIT_POS) != GpioHardwareDefault) {
+
+ IntRouteValue = ((Value & GPIO_CONF_INT_ROUTE_MASK) >> (GPIO_CONF_INT_ROUTE_BIT_POS + 1)) << N_PCH_GPIO_RX_NMI_ROUTE;
+
+ Status = GpioReadWritePadCfgReg (
+ GpioPad,
+ 0,
+ (B_PCH_GPIO_RX_NMI_ROUTE | B_PCH_GPIO_RX_SCI_ROUTE | B_PCH_GPIO_RX_SMI_ROUTE | B_PCH_GPIO_RX_APIC_ROUTE),
+ TRUE,
+ &IntRouteValue
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if ((Value & GpioIntSci) == GpioIntSci) {
+ GpeEnable = 0x1;
+ } else {
+ GpeEnable = 0x0;
+ }
+
+ Status = GpioReadWriteReg (
+ GpioGpeEnableRegister,
+ 0,
+ 0,
+ GpioPad,
+ TRUE,
+ TRUE,
+ &GpeEnable
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ return Status;
+}
+
+/**
+ This procedure will set GPIO electrical settings
+
+ @param[in] GpioPad GPIO pad
+ @param[in] Value Value of termination
+ use GPIO_ELECTRICAL_CONFIG as argument
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or pad number
+**/
+EFI_STATUS
+GpioSetPadElectricalConfig (
+ IN GPIO_PAD GpioPad,
+ IN GPIO_ELECTRICAL_CONFIG Value
+ )
+{
+ EFI_STATUS Status;
+ UINT32 TermValue;
+ UINT32 PadTolValue;
+
+ Status = EFI_SUCCESS;
+
+ if (((Value & GPIO_CONF_TERM_MASK) >> GPIO_CONF_TERM_BIT_POS) != GpioHardwareDefault) {
+ TermValue = ((Value & GPIO_CONF_TERM_MASK) >> (GPIO_CONF_TERM_BIT_POS + 1)) << N_PCH_GPIO_TERM;
+
+ Status = GpioReadWritePadCfgReg (
+ GpioPad,
+ 1,
+ B_PCH_GPIO_TERM,
+ TRUE,
+ &TermValue
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ if (((Value & GPIO_CONF_PADTOL_MASK) >> GPIO_CONF_PADTOL_BIT_POS) != GpioHardwareDefault) {
+ PadTolValue = ((Value & GPIO_CONF_PADTOL_MASK) >> (GPIO_CONF_PADTOL_BIT_POS + 1)) << N_PCH_GPIO_PADTOL;
+
+ Status = GpioReadWritePadCfgReg (
+ GpioPad,
+ 1,
+ B_PCH_GPIO_PADTOL,
+ TRUE,
+ &PadTolValue
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ return Status;
+}
+
+/**
+ This procedure will set GPIO Reset settings
+
+ @param[in] GpioPad GPIO pad
+ @param[in] Value Value for Pad Reset Configuration
+ use GPIO_RESET_CONFIG as argument
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or pad number
+**/
+EFI_STATUS
+GpioSetPadResetConfig (
+ IN GPIO_PAD GpioPad,
+ IN GPIO_RESET_CONFIG Value
+ )
+{
+ EFI_STATUS Status;
+ UINT32 ResetValue;
+
+ Status = EFI_SUCCESS;
+
+ if (((Value & GPIO_CONF_RESET_MASK) >> GPIO_CONF_RESET_BIT_POS) != GpioHardwareDefault) {
+ ResetValue = ((Value & GPIO_CONF_RESET_MASK) >> (GPIO_CONF_RESET_BIT_POS + 1)) << N_PCH_GPIO_RST_CONF;
+
+ Status = GpioReadWritePadCfgReg (
+ GpioPad,
+ 0,
+ B_PCH_GPIO_RST_CONF,
+ TRUE,
+ &ResetValue
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ return Status;
+}
+
+/**
+ This procedure will get GPIO Reset settings
+
+ @param[in] GpioPad GPIO pad
+ @param[in] Value Value of Pad Reset Configuration
+ based on GPIO_RESET_CONFIG
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or pad number
+**/
+EFI_STATUS
+GpioGetPadResetConfig (
+ IN GPIO_PAD GpioPad,
+ IN GPIO_RESET_CONFIG *Value
+ )
+{
+ EFI_STATUS Status;
+ UINT32 ResetValue;
+
+ Status = GpioReadWritePadCfgReg (
+ GpioPad,
+ 0,
+ B_PCH_GPIO_RST_CONF,
+ FALSE,
+ &ResetValue
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Get Reset Type (PadRstCfg)
+ //
+ *Value = (ResetValue >> (N_PCH_GPIO_RST_CONF - (GPIO_CONF_RESET_BIT_POS + 1))) | (0x1 << GPIO_CONF_RESET_BIT_POS);
+
+ return Status;
+}
+
+/**
+ This procedure will get GPIO Host Software Pad Ownership for certain group
+
+ @param[in] Group GPIO group
+ @param[in] DwNum Host Ownership register number for current group.
+ For group which has less then 32 pads per group DwNum must be 0.
+ @param[out] HostSwRegVal Value of Host Software Pad Ownership register
+ Bit position - PadNumber
+ Bit value - 0: ACPI Mode, 1: GPIO Driver mode
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or DwNum parameter number
+**/
+EFI_STATUS
+GpioGetHostSwOwnershipForGroupDw (
+ IN GPIO_GROUP Group,
+ IN UINT32 DwNum,
+ OUT UINT32 *HostSwRegVal
+ )
+{
+ EFI_STATUS Status;
+
+ Status = GpioReadWriteReg (
+ GpioHostOwnershipRegister,
+ Group,
+ DwNum,
+ 0,
+ FALSE,
+ FALSE,
+ HostSwRegVal
+ );
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
+
+/**
+ This procedure will get GPIO Host Software Pad Ownership for certain group
+
+ @param[in] Group GPIO group
+ @param[in] DwNum Host Ownership register number for current group
+ For group which has less then 32 pads per group DwNum must be 0.
+ @param[in] HostSwRegVal Value of Host Software Pad Ownership register
+ Bit position - PadNumber
+ Bit value - 0: ACPI Mode, 1: GPIO Driver mode
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or DwNum parameter number
+**/
+EFI_STATUS
+GpioSetHostSwOwnershipForGroupDw (
+ IN GPIO_GROUP Group,
+ IN UINT32 DwNum,
+ IN UINT32 HostSwRegVal
+ )
+{
+ EFI_STATUS Status;
+
+ Status = GpioReadWriteReg (
+ GpioHostOwnershipRegister,
+ Group,
+ DwNum,
+ 0,
+ TRUE,
+ FALSE,
+ &HostSwRegVal
+ );
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
+
+/**
+ This procedure will get Gpio Pad Host Software Ownership
+
+ @param[in] GpioPad GPIO pad
+ @param[out] PadHostSwOwn Value of Host Software Pad Owner
+ 0: ACPI Mode, 1: GPIO Driver mode
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or pad number
+**/
+EFI_STATUS
+GpioGetHostSwOwnershipForPad (
+ IN GPIO_PAD GpioPad,
+ OUT UINT32 *PadHostSwOwn
+ )
+{
+ EFI_STATUS Status;
+
+ Status = GpioReadWriteReg (
+ GpioHostOwnershipRegister,
+ 0,
+ 0,
+ GpioPad,
+ FALSE,
+ TRUE,
+ PadHostSwOwn
+ );
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
+
+/**
+ This procedure will set Gpio Pad Host Software Ownership
+
+ @param[in] GpioPad GPIO pad
+ @param[in] PadHostSwOwn Pad Host Software Owner
+ 0: ACPI Mode, 1: GPIO Driver mode
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or pad number
+**/
+EFI_STATUS
+GpioSetHostSwOwnershipForPad (
+ IN GPIO_PAD GpioPad,
+ IN UINT32 PadHostSwOwn
+ )
+{
+ EFI_STATUS Status;
+
+ Status = GpioReadWriteReg (
+ GpioHostOwnershipRegister,
+ 0,
+ 0,
+ GpioPad,
+ TRUE,
+ TRUE,
+ &PadHostSwOwn
+ );
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
+
+/**
+ This procedure will get Gpio Pad Ownership
+
+ @param[in] GpioPad GPIO pad
+ @param[out] PadOwnVal Value of Pad Ownership
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or pad number
+**/
+EFI_STATUS
+GpioGetPadOwnership (
+ IN GPIO_PAD GpioPad,
+ OUT GPIO_PAD_OWN *PadOwnVal
+ )
+{
+ UINT32 Mask;
+ UINT32 RegOffset;
+ UINT32 GroupIndex;
+ UINT32 PadNumber;
+ GPIO_GROUP_INFO *GpioGroupInfo;
+ UINTN GpioGroupInfoLength;
+ UINT32 PadOwnRegValue;
+
+ GroupIndex = GpioGetGroupIndexFromGpioPad (GpioPad);
+ PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
+
+ GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
+
+ //
+ // Check if group argument exceeds GPIO GROUP INFO array
+ //
+ if ((UINTN)GroupIndex >= GpioGroupInfoLength) {
+ DEBUG ((DEBUG_ERROR, "GPIO ERROR: Group argument (%d) exceeds GPIO group range\n", GroupIndex));
+ ASSERT(FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check if legal pin number
+ //
+ if (PadNumber >= GpioGroupInfo[GroupIndex].PadPerGroup) {
+ DEBUG ((DEBUG_ERROR, "GPIO ERROR: Pin number (%d) exceeds possible range for this group\n", PadNumber));
+ ASSERT(FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Calculate RegOffset using Pad Ownership offset and GPIO Pad number.
+ // One DWord register contains information for 8 pads.
+ //
+ RegOffset = GpioGroupInfo[GroupIndex].PadOwnOffset + (PadNumber >> 3) * 0x4;
+
+ //
+ // Calculate pad bit position within DWord register
+ //
+ PadNumber %= 8;
+ Mask = (BIT1 | BIT0) << (PadNumber * 4);
+
+ PadOwnRegValue = MmioRead32 (PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, RegOffset));
+
+ *PadOwnVal = (GPIO_PAD_OWN)((PadOwnRegValue & Mask) >> (PadNumber * 4));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This procedure will check state of Pad Config Lock for pads within one group
+
+ @param[in] Group GPIO group
+ @param[in] DwNum PadCfgLock register number for current group.
+ For group which has less then 32 pads per group DwNum must be 0.
+ @param[out] PadCfgLockRegVal Value of PadCfgLock register
+ Bit position - PadNumber
+ Bit value - 0: NotLocked, 1: Locked
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or DwNum parameter number
+**/
+EFI_STATUS
+GpioGetPadCfgLockForGroupDw (
+ IN GPIO_GROUP Group,
+ IN UINT32 DwNum,
+ OUT UINT32 *PadCfgLockRegVal
+ )
+{
+ EFI_STATUS Status;
+
+ Status = GpioReadWriteReg (
+ GpioPadConfigLockRegister,
+ Group,
+ DwNum,
+ 0,
+ FALSE,
+ FALSE,
+ PadCfgLockRegVal
+ );
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
+
+/**
+ This procedure will check state of Pad Config Lock for selected pad
+
+ @param[in] GpioPad GPIO pad
+ @param[out] PadCfgLock PadCfgLock for selected pad
+ 0: NotLocked, 1: Locked
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or pad number
+**/
+EFI_STATUS
+GpioGetPadCfgLock (
+ IN GPIO_PAD GpioPad,
+ OUT UINT32 *PadCfgLock
+ )
+{
+ EFI_STATUS Status;
+
+ Status = GpioReadWriteReg (
+ GpioPadConfigLockRegister,
+ 0,
+ 0,
+ GpioPad,
+ FALSE,
+ TRUE,
+ PadCfgLock
+ );
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
+
+/**
+ This procedure will check state of Pad Config Tx Lock for pads within one group
+
+ @param[in] Group GPIO group
+ @param[in] DwNum PadCfgLockTx register number for current group.
+ For group which has less then 32 pads per group DwNum must be 0.
+ @param[out] PadCfgLockTxRegVal Value of PadCfgLockTx register
+ Bit position - PadNumber
+ Bit value - 0: NotLockedTx, 1: LockedTx
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or DwNum parameter number
+**/
+EFI_STATUS
+GpioGetPadCfgLockTxForGroupDw (
+ IN GPIO_GROUP Group,
+ IN UINT32 DwNum,
+ OUT UINT32 *PadCfgLockTxRegVal
+ )
+{
+ EFI_STATUS Status;
+
+ Status = GpioReadWriteReg (
+ GpioPadLockOutputRegister,
+ Group,
+ DwNum,
+ 0,
+ FALSE,
+ FALSE,
+ PadCfgLockTxRegVal
+ );
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
+
+/**
+ This procedure will check state of Pad Config Tx Lock for selected pad
+
+ @param[in] GpioPad GPIO pad
+ @param[out] PadCfgLock PadCfgLockTx for selected pad
+ 0: NotLockedTx, 1: LockedTx
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or pad number
+**/
+EFI_STATUS
+GpioGetPadCfgLockTx (
+ IN GPIO_PAD GpioPad,
+ OUT UINT32 *PadCfgLockTx
+ )
+{
+ EFI_STATUS Status;
+
+ Status = GpioReadWriteReg (
+ GpioPadLockOutputRegister,
+ 0,
+ 0,
+ GpioPad,
+ FALSE,
+ TRUE,
+ PadCfgLockTx
+ );
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
+
+/**
+ This procedure will clear PadCfgLock for selected pads within one group.
+ This function should be used only inside SMI.
+
+ @param[in] Group GPIO group
+ @param[in] DwNum PadCfgLock register number for current group.
+ For group which has less then 32 pads per group DwNum must be 0.
+ @param[in] PadsToUnlock Bitmask for pads which are going to be unlocked,
+ Bit position - PadNumber
+ Bit value - 0: DoNotUnlock, 1: Unlock
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or pad number
+**/
+EFI_STATUS
+GpioUnlockPadCfgForGroupDw (
+ IN GPIO_GROUP Group,
+ IN UINT32 DwNum,
+ IN UINT32 PadsToUnlock
+ )
+{
+ EFI_STATUS Status;
+
+ Status = GpioLockPadsUsingSbi (
+ GpioPadConfigLockRegister,
+ TRUE,
+ Group,
+ DwNum,
+ PadsToUnlock,
+ 0,
+ FALSE
+ );
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
+
+/**
+ This procedure will clear PadCfgLock for selected pad.
+ This function should be used only inside SMI.
+
+ @param[in] GpioPad GPIO pad
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or pad number
+**/
+EFI_STATUS
+GpioUnlockPadCfg (
+ IN GPIO_PAD GpioPad
+ )
+{
+ EFI_STATUS Status;
+
+ Status = GpioLockPadsUsingSbi (
+ GpioPadConfigLockRegister,
+ TRUE,
+ 0,
+ 0,
+ 0,
+ GpioPad,
+ TRUE
+ );
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
+
+/**
+ This procedure will set PadCfgLock for selected pads within one group
+
+ @param[in] Group GPIO group
+ @param[in] DwNum PadCfgLock register number for current group.
+ For group which has less then 32 pads per group DwNum must be 0.
+ @param[in] PadsToLock Bitmask for pads which are going to be locked
+ Bit position - PadNumber
+ Bit value - 0: DoNotLock, 1: Lock
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or DwNum parameter number
+**/
+EFI_STATUS
+GpioLockPadCfgForGroupDw (
+ IN GPIO_GROUP Group,
+ IN UINT32 DwNum,
+ IN UINT32 PadsToLock
+ )
+{
+ EFI_STATUS Status;
+
+ Status = GpioLockPadsUsingSbi (
+ GpioPadConfigLockRegister,
+ FALSE,
+ Group,
+ DwNum,
+ PadsToLock,
+ 0,
+ FALSE
+ );
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
+
+/**
+ This procedure will set PadCfgLock for selected pad
+
+ @param[in] GpioPad GPIO pad
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or pad number
+**/
+EFI_STATUS
+GpioLockPadCfg (
+ IN GPIO_PAD GpioPad
+ )
+{
+ EFI_STATUS Status;
+
+ Status = GpioLockPadsUsingSbi (
+ GpioPadConfigLockRegister,
+ FALSE,
+ 0,
+ 0,
+ 0,
+ GpioPad,
+ TRUE
+ );
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
+
+/**
+ This procedure will clear PadCfgLockTx for selected pads within one group.
+ This function should be used only inside SMI.
+
+ @param[in] Group GPIO group
+ @param[in] DwNum PadCfgLockTx register number for current group.
+ For group which has less then 32 pads per group DwNum must be 0.
+ @param[in] PadsToUnlockTx Bitmask for pads which are going to be unlocked,
+ Bit position - PadNumber
+ Bit value - 0: DoNotUnLockTx, 1: LockTx
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or pad number
+**/
+EFI_STATUS
+GpioUnlockPadCfgTxForGroupDw (
+ IN GPIO_GROUP Group,
+ IN UINT32 DwNum,
+ IN UINT32 PadsToUnlockTx
+ )
+{
+ EFI_STATUS Status;
+
+ Status = GpioLockPadsUsingSbi (
+ GpioPadLockOutputRegister,
+ TRUE,
+ Group,
+ DwNum,
+ PadsToUnlockTx,
+ 0,
+ FALSE
+ );
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
+
+/**
+ This procedure will clear PadCfgLockTx for selected pad.
+ This function should be used only inside SMI.
+
+ @param[in] GpioPad GPIO pad
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or pad number
+**/
+EFI_STATUS
+GpioUnlockPadCfgTx (
+ IN GPIO_PAD GpioPad
+ )
+{
+ EFI_STATUS Status;
+
+ Status = GpioLockPadsUsingSbi (
+ GpioPadLockOutputRegister,
+ TRUE,
+ 0,
+ 0,
+ 0,
+ GpioPad,
+ TRUE
+ );
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
+
+/**
+ This procedure will set PadCfgLockTx for selected pads within one group
+
+ @param[in] Group GPIO group
+ @param[in] DwNum PadCfgLock register number for current group.
+ For group which has less then 32 pads per group DwNum must be 0.
+ @param[in] PadsToLockTx Bitmask for pads which are going to be locked,
+ Bit position - PadNumber
+ Bit value - 0: DoNotLockTx, 1: LockTx
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or DwNum parameter number
+**/
+EFI_STATUS
+GpioLockPadCfgTxForGroupDw (
+ IN GPIO_GROUP Group,
+ IN UINT32 DwNum,
+ IN UINT32 PadsToLockTx
+ )
+{
+ EFI_STATUS Status;
+
+ Status = GpioLockPadsUsingSbi (
+ GpioPadLockOutputRegister,
+ FALSE,
+ Group,
+ DwNum,
+ PadsToLockTx,
+ 0,
+ FALSE
+ );
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
+
+/**
+ This procedure will set PadCfgLockTx for selected pad
+
+ @param[in] GpioPad GPIO pad
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or pad number
+**/
+EFI_STATUS
+GpioLockPadCfgTx (
+ IN GPIO_PAD GpioPad
+ )
+{
+ EFI_STATUS Status;
+
+ Status = GpioLockPadsUsingSbi (
+ GpioPadLockOutputRegister,
+ FALSE,
+ 0,
+ 0,
+ 0,
+ GpioPad,
+ TRUE
+ );
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
+
+
+/**
+ This procedure will get Group to GPE mapping.
+
+ @param[out] GroupToGpeDw0 GPIO group to be mapped to GPE_DW0
+ @param[out] GroupToGpeDw1 GPIO group to be mapped to GPE_DW1
+ @param[out] GroupToGpeDw2 GPIO group to be mapped to GPE_DW2
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or pad number
+**/
+EFI_STATUS
+GpioGetGroupToGpeDwX (
+ IN GPIO_GROUP *GroupToGpeDw0,
+ IN GPIO_GROUP *GroupToGpeDw1,
+ IN GPIO_GROUP *GroupToGpeDw2
+ )
+{
+ UINT32 Data32;
+ UINT32 PchPwrmBase;
+ GPIO_GROUP GpioGroupOffset;
+
+ GpioGroupOffset = GpioGetLowestGroup ();
+
+
+ PchPwrmBaseGet (&PchPwrmBase);
+
+ Data32 = MmioRead32 ((UINTN) (PchPwrmBase + R_PCH_PWRM_GPIO_CFG));
+
+ *GroupToGpeDw0 = ((Data32 & B_PCH_PWRM_GPIO_CFG_GPE0_DW0) >> N_PCH_PWRM_GPIO_CFG_GPE0_DW0) + GpioGroupOffset;
+ *GroupToGpeDw1 = ((Data32 & B_PCH_PWRM_GPIO_CFG_GPE0_DW1) >> N_PCH_PWRM_GPIO_CFG_GPE0_DW1) + GpioGroupOffset;
+ *GroupToGpeDw2 = ((Data32 & B_PCH_PWRM_GPIO_CFG_GPE0_DW2) >> N_PCH_PWRM_GPIO_CFG_GPE0_DW2) + GpioGroupOffset;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This procedure will set Group to GPE mapping.
+
+ @param[in] GroupToGpeDw0 GPIO group to be mapped to GPE_DW0
+ @param[in] GroupToGpeDw1 GPIO group to be mapped to GPE_DW1
+ @param[in] GroupToGpeDw2 GPIO group to be mapped to GPE_DW2
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or pad number
+**/
+EFI_STATUS
+GpioSetGroupToGpeDwX (
+ IN GPIO_GROUP GroupToGpeDw0,
+ IN GPIO_GROUP GroupToGpeDw1,
+ IN GPIO_GROUP GroupToGpeDw2
+ )
+{
+ UINT32 Data32Or;
+ UINT32 Data32And;
+ UINT32 PchPwrmBase;
+ GPIO_GROUP GpioGroupLowest;
+ GPIO_GROUP GpioGroupHighest;
+
+ GpioGroupLowest = GpioGetLowestGroup ();
+ GpioGroupHighest = GpioGetHighestGroup ();
+
+ //
+ // Check if group argument exceeds GPIO group range
+ //
+ if (((UINT32)GroupToGpeDw0 < GpioGroupLowest) || ((UINT32)GroupToGpeDw0 > GpioGroupHighest) ||
+ ((UINT32)GroupToGpeDw1 < GpioGroupLowest) || ((UINT32)GroupToGpeDw1 > GpioGroupHighest) ||
+ ((UINT32)GroupToGpeDw2 < GpioGroupLowest) || ((UINT32)GroupToGpeDw2 > GpioGroupHighest)) {
+ DEBUG ((DEBUG_ERROR, "GPIO ERROR: Group argument exceeds GPIO group range\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check if each group number is unique
+ //
+ if ((GroupToGpeDw0 == GroupToGpeDw1) ||
+ (GroupToGpeDw0 == GroupToGpeDw2) ||
+ (GroupToGpeDw1 == GroupToGpeDw2)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Values in GPE0_DWx registers are 0 based (GPP_A = 0h)
+ //
+ GroupToGpeDw0 = GpioGetGroupIndexFromGroup(GroupToGpeDw0);
+ GroupToGpeDw1 = GpioGetGroupIndexFromGroup(GroupToGpeDw1);
+ GroupToGpeDw2 = GpioGetGroupIndexFromGroup(GroupToGpeDw2);
+
+ PchPwrmBaseGet (&PchPwrmBase);
+
+ //
+ // Program GPIO_CFG (PMRMBASE + 120h) register
+ //
+ Data32And = (UINT32) ~(B_PCH_PWRM_GPIO_CFG_GPE0_DW2 | B_PCH_PWRM_GPIO_CFG_GPE0_DW1 | B_PCH_PWRM_GPIO_CFG_GPE0_DW0);
+ Data32Or = (UINT32)((GroupToGpeDw2 << N_PCH_PWRM_GPIO_CFG_GPE0_DW2) |
+ (GroupToGpeDw1 << N_PCH_PWRM_GPIO_CFG_GPE0_DW1) |
+ (GroupToGpeDw0 << N_PCH_PWRM_GPIO_CFG_GPE0_DW0));
+
+ MmioAndThenOr32 (
+ (UINTN) (PchPwrmBase + R_PCH_PWRM_GPIO_CFG),
+ Data32And,
+ Data32Or
+ );
+
+ Data32And = (UINT32) ~(B_PCH_PCR_GPIO_MISCCFG_GPE0_DW2 | B_PCH_PCR_GPIO_MISCCFG_GPE0_DW1 | B_PCH_PCR_GPIO_MISCCFG_GPE0_DW0);
+ Data32Or = (UINT32)((GroupToGpeDw2 << N_PCH_PCR_GPIO_MISCCFG_GPE0_DW2) |
+ (GroupToGpeDw1 << N_PCH_PCR_GPIO_MISCCFG_GPE0_DW1) |
+ (GroupToGpeDw0 << N_PCH_PCR_GPIO_MISCCFG_GPE0_DW0));
+ //
+ // Program MISCCFG register for Community 0
+ //
+ MmioAndThenOr32 (
+ (UINTN)PCH_PCR_ADDRESS (PID_GPIOCOM0, R_PCH_PCR_GPIO_MISCCFG),
+ Data32And,
+ Data32Or
+ );
+
+ //
+ // Program MISCCFG register for Community 1
+ //
+ MmioAndThenOr32 (
+ (UINTN)PCH_PCR_ADDRESS (PID_GPIOCOM1, R_PCH_PCR_GPIO_MISCCFG),
+ Data32And,
+ Data32Or
+ );
+
+ //
+ // Program MISCCFG register for Community 2
+ //
+ MmioAndThenOr32 (
+ (UINTN)PCH_PCR_ADDRESS (PID_GPIOCOM2, R_PCH_PCR_GPIO_MISCCFG),
+ Data32And,
+ Data32Or
+ );
+
+ //
+ // Program MISCCFG register for Community 3
+ //
+ MmioAndThenOr32 (
+ (UINTN)PCH_PCR_ADDRESS (PID_GPIOCOM3, R_PCH_PCR_GPIO_MISCCFG),
+ Data32And,
+ Data32Or
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This procedure will get GPE number for provided GpioPad.
+ PCH allows to configure mapping between GPIO groups and related GPE (GpioSetGroupToGpeDwX())
+ what results in the fact that certain Pad can cause different General Purpose Event. Only three
+ GPIO groups can be mapped to cause unique GPE (1-tier), all others groups will be under one common
+ event (GPE_111 for 2-tier).
+
+ 1-tier:
+ Returned GpeNumber is in range <0,95>. GpioGetGpeNumber() can be used
+ to determine what _LXX ACPI method would be called on event on selected GPIO pad
+
+ 2-tier:
+ Returned GpeNumber is 0x6F (111). All GPIO pads which are not mapped to 1-tier GPE
+ will be under one master GPE_111 which is linked to _L6F ACPI method. If it is needed to determine
+ what Pad from 2-tier has caused the event, _L6F method should check GPI_GPE_STS and GPI_GPE_EN
+ registers for all GPIO groups not mapped to 1-tier GPE.
+
+ @param[in] GpioPad GPIO pad
+ @param[out] GpeNumber GPE number
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or pad number
+**/
+EFI_STATUS
+GpioGetGpeNumber (
+ IN GPIO_PAD GpioPad,
+ OUT UINT32 *GpeNumber
+ )
+{
+ GPIO_GROUP GroupToGpeDw0;
+ GPIO_GROUP GroupToGpeDw1;
+ GPIO_GROUP GroupToGpeDw2;
+ GPIO_GROUP GpioGroupLowest;
+ GPIO_GROUP GpioGroupHighest;
+ UINT32 GroupIndex;
+ GPIO_GROUP Group;
+ UINT32 PadNumber;
+ GPIO_GROUP_INFO *GpioGroupInfo;
+ UINTN GpioGroupInfoLength;
+
+ GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
+
+ Group = GpioGetGroupFromGpioPad (GpioPad);
+ GroupIndex = GpioGetGroupIndexFromGpioPad (GpioPad);
+ PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
+
+DEBUG_CODE_BEGIN();
+ if (!GpioIsCorrectPadForThisChipset (GpioPad)) {
+ DEBUG ((DEBUG_ERROR, "GPIO ERROR: Incorrect GpioPad define used on this chipset (Group=%d, Pad=%d)!\n", GroupIndex, PadNumber));
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+DEBUG_CODE_END();
+
+ GpioGroupLowest = GpioGetLowestGroup ();
+ GpioGroupHighest = GpioGetHighestGroup ();
+
+ //
+ // Check if group argument exceeds GPIO group range
+ //
+ if ((GroupIndex < GpioGetGroupIndexFromGroup (GpioGroupLowest)) || (GroupIndex > GpioGetGroupIndexFromGroup (GpioGroupHighest))) {
+ DEBUG ((DEBUG_ERROR, "GPIO ERROR: Group argument (%d) exceeds GPIO group range\n", GroupIndex));
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check if legal pad number
+ //
+ if (PadNumber >= GpioGroupInfo[GroupIndex].PadPerGroup) {
+ DEBUG ((DEBUG_ERROR, "GPIO ERROR: Pin number (%d) exceeds possible range for this group\n", PadNumber));
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get GPIO groups mapping to 1-tier GPE
+ //
+ GpioGetGroupToGpeDwX (&GroupToGpeDw0,&GroupToGpeDw1,&GroupToGpeDw2);
+
+ if (Group == GroupToGpeDw0) {
+ *GpeNumber = PadNumber;
+ } else if (Group== GroupToGpeDw1) {
+ *GpeNumber = PadNumber + 32;
+ } else if (Group == GroupToGpeDw2) {
+ *GpeNumber = PadNumber + 64;
+ } else {
+ //
+ // If Group number doesn't match any of above then
+ // it means than certain pad is routed to 2-tier GPE
+ // which all are under GPE_111 (0x6F)
+ //
+ *GpeNumber = PCH_GPIO_2_TIER_MASTER_GPE_NUMBER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This procedure is used to clear SMI STS for a specified Pad
+
+ @param[in] GpioPad GPIO pad
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or pad number
+**/
+EFI_STATUS
+GpioClearGpiSmiSts (
+ IN GPIO_PAD GpioPad
+ )
+{
+ UINT32 GroupIndex;
+ UINT32 PadNumber;
+ GPIO_GROUP_INFO *GpioGroupInfo;
+ UINTN GpioGroupInfoLength;
+
+ GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
+
+ GroupIndex = GpioGetGroupIndexFromGpioPad (GpioPad);
+ PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
+
+DEBUG_CODE_BEGIN();
+ if (!GpioIsCorrectPadForThisChipset (GpioPad)) {
+ DEBUG ((DEBUG_ERROR, "GPIO ERROR: Incorrect GpioPad define used on this chipset (Group=%d, Pad=%d)!\n", GroupIndex, PadNumber));
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+DEBUG_CODE_END();
+
+ //
+ // Check if group argument exceeds GPIO GROUP INFO array
+ //
+ if ((UINTN)GroupIndex >= GpioGroupInfoLength) {
+ DEBUG ((DEBUG_ERROR, "GPIO ERROR: Group argument (%d) exceeds GPIO group range\n", GroupIndex));
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check if legal pad number
+ //
+ if (PadNumber >= GpioGroupInfo[GroupIndex].PadPerGroup) {
+ DEBUG ((DEBUG_ERROR, "GPIO ERROR: Pin number (%d) exceeds possible range for this group\n", PadNumber));
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check if group has GPI SMI register
+ //
+ if (GpioGroupInfo[GroupIndex].SmiStsOffset == NO_REGISTER_FOR_PROPERTY) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Clear all GPI SMI Status bits by writing '1'
+ //
+ MmioWrite32 (
+ PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, GpioGroupInfo[GroupIndex].SmiStsOffset),
+ (UINT32)(BIT0 << PadNumber)
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This procedure is used by PchSmiDispatcher and will clear
+ all GPI SMI Status bits
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or pad number
+**/
+EFI_STATUS
+GpioClearAllGpiSmiSts (
+ VOID
+ )
+{
+ UINT32 GroupIndex;
+ GPIO_GROUP_INFO *GpioGroupInfo;
+ UINTN GpioGroupInfoLength;
+
+ GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
+
+ for (GroupIndex = 0; GroupIndex < GpioGroupInfoLength; GroupIndex++) {
+ //
+ // Check if group has GPI SMI register
+ //
+ if (GpioGroupInfo[GroupIndex].SmiStsOffset == NO_REGISTER_FOR_PROPERTY) {
+ continue;
+ }
+ //
+ // Clear all GPI SMI Status bits by writing '1'
+ //
+ MmioWrite32 (
+ PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, GpioGroupInfo[GroupIndex].SmiStsOffset),
+ (UINT32)0xFFFFFFFF
+ );
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ This procedure is used to disable all GPI SMI
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or pad number
+**/
+EFI_STATUS
+GpioDisableAllGpiSmi (
+ VOID
+ )
+{
+ GPIO_GROUP_INFO *GpioGroupInfo;
+ UINT32 GroupIndex;
+ UINTN GpioGroupInfoLength;
+
+ GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
+
+ for (GroupIndex = 0; GroupIndex < GpioGroupInfoLength; GroupIndex++) {
+ //
+ // Check if group has GPI SMI register
+ //
+ if (GpioGroupInfo[GroupIndex].SmiEnOffset == NO_REGISTER_FOR_PROPERTY) {
+ continue;
+ }
+
+ //
+ // Disable all GPI SMI
+ //
+ MmioWrite32 (
+ PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, GpioGroupInfo[GroupIndex].SmiEnOffset),
+ (UINT32)0x0
+ );
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ This procedure is used to register GPI SMI dispatch function.
+
+ @param[in] GpioPad GPIO pad
+ @param[out] GpiNum GPI number
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or pad number
+**/
+EFI_STATUS
+GpioGetGpiSmiNum (
+ IN GPIO_PAD GpioPad,
+ OUT UINTN *GpiNum
+ )
+{
+ UINT32 GroupIndex;
+ UINT32 Index;
+ UINT32 PadNumber;
+ GPIO_GROUP_INFO *GpioGroupInfo;
+ UINTN GpioGroupInfoLength;
+
+ GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
+
+ GroupIndex = GpioGetGroupIndexFromGpioPad (GpioPad);
+ PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
+
+DEBUG_CODE_BEGIN();
+ if (!GpioIsCorrectPadForThisChipset (GpioPad)) {
+ DEBUG ((DEBUG_ERROR, "GPIO ERROR: Incorrect GpioPad define used on this chipset (Group=%d, Pad=%d)!\n", GroupIndex, PadNumber));
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+DEBUG_CODE_END();
+
+ //
+ // Check if group argument exceeds GPIO GROUP INFO array
+ //
+ if ((UINTN)GroupIndex >= GpioGroupInfoLength) {
+ DEBUG ((DEBUG_ERROR, "GPIO ERROR: Group argument (%d) exceeds GPIO group range\n", GroupIndex));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check if legal pad number
+ //
+ if (PadNumber >= GpioGroupInfo[GroupIndex].PadPerGroup){
+ DEBUG ((DEBUG_ERROR, "GPIO ERROR: Pin number (%d) exceeds possible range for this group\n", PadNumber));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *GpiNum = 0;
+
+ for (Index = 0; Index < (UINT32)GroupIndex; Index++) {
+ *GpiNum += (UINTN)(GpioGroupInfo[Index].PadPerGroup);
+ }
+ *GpiNum += (UINTN)PadNumber;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This procedure is used to check GPIO inputs belongs to 2 tier or 1 tier architecture
+
+ @param[in] GpioPad GPIO pad
+
+ @retval Data 0 means 1-tier, 1 means 2-tier
+**/
+BOOLEAN
+GpioCheckFor2Tier (
+ IN GPIO_PAD GpioPad
+ )
+{
+ UINT32 Data32;
+
+ GpioGetGpeNumber (GpioPad, &Data32);
+ if(Data32 == PCH_GPIO_2_TIER_MASTER_GPE_NUMBER) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ This procedure is used to clear GPE STS for a specified GpioPad
+
+ @param[in] GpioPad GPIO pad
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or pad number
+**/
+EFI_STATUS
+GpioClearGpiGpeSts (
+ IN GPIO_PAD GpioPad
+ )
+{
+ UINT32 GroupIndex;
+ UINT32 PadNumber;
+ GPIO_GROUP_INFO *GpioGroupInfo;
+ UINTN GpioGroupInfoLength;
+
+ GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
+
+ GroupIndex = GpioGetGroupIndexFromGpioPad (GpioPad);
+ PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
+
+ //
+ // Check if group argument exceeds GPIO GROUP INFO array
+ //
+ if ((UINTN)GroupIndex >= GpioGroupInfoLength) {
+ DEBUG ((DEBUG_ERROR, "GPIO ERROR: Group argument (%d) exceeds GPIO group range\n", GroupIndex));
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check if legal pad number
+ //
+ if (PadNumber >= GpioGroupInfo[GroupIndex].PadPerGroup) {
+ DEBUG ((DEBUG_ERROR, "GPIO ERROR: Pin number (%d) exceeds possible range for this group\n", PadNumber));
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check if group has GPI GPE register
+ //
+ if (GpioGroupInfo[GroupIndex].GpiGpeStsOffset == NO_REGISTER_FOR_PROPERTY) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Check for 2-tier
+ if(!(GpioCheckFor2Tier (GpioPad))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Clear all GPI SMI Status bits by writing '1'
+ //
+ MmioWrite32 (
+ PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, GpioGroupInfo[GroupIndex].GpiGpeStsOffset),
+ (UINT32)(BIT0 << PadNumber)
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This procedure is used to read GPE STS for a specified Pad
+
+ @param[in] GpioPad GPIO pad
+ @param[out] Data GPE STS data
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or pad number
+**/
+EFI_STATUS
+GpioGetGpiGpeSts (
+ IN GPIO_PAD GpioPad,
+ OUT UINT32* Data
+ )
+{
+ UINT32 Data32;
+ UINT32 Mask;
+ UINT32 GroupIndex;
+ UINT32 PadNumber;
+ GPIO_GROUP_INFO *GpioGroupInfo;
+ UINTN GpioGroupInfoLength;
+
+ *Data = 0xFFFFFFFF;
+
+ GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
+
+ GroupIndex = GpioGetGroupIndexFromGpioPad (GpioPad);
+ PadNumber = GpioGetPadNumberFromGpioPad (GpioPad);
+
+ //
+ // Check if group argument exceeds GPIO GROUP INFO array
+ //
+ if ((UINTN)GroupIndex >= GpioGroupInfoLength) {
+ DEBUG ((DEBUG_ERROR, "GPIO ERROR: Group argument (%d) exceeds GPIO group range\n", GroupIndex));
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check if legal pad number
+ //
+ if (PadNumber >= GpioGroupInfo[GroupIndex].PadPerGroup) {
+ DEBUG ((DEBUG_ERROR, "GPIO ERROR: Pin number (%d) exceeds possible range for this group\n", PadNumber));
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check if group has GPI GPE register
+ //
+ if (GpioGroupInfo[GroupIndex].GpiGpeStsOffset == NO_REGISTER_FOR_PROPERTY) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Check for 2-tier
+ if(!(GpioCheckFor2Tier (GpioPad))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Read GPI GPE Status bits
+ //
+ Data32 = MmioRead32(
+ PCH_PCR_ADDRESS(GpioGroupInfo[GroupIndex].Community, GpioGroupInfo[GroupIndex].GpiGpeStsOffset)
+ );
+
+ Mask = (UINT32)(BIT0 << PadNumber);
+ Data32 = (Data32 & Mask) >> PadNumber;
+ *Data = Data32;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This procedure will set GPIO Input Rout SCI
+
+ @param[in] GpioPad GPIO pad
+ @param[in] Value Value for GPIRoutSCI
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or pad number
+**/
+EFI_STATUS
+GpioSetGpiRoutSci (
+ IN GPIO_PAD GpioPad,
+ IN UINT32 Value
+ )
+{
+ EFI_STATUS Status;
+
+ Value <<= N_PCH_GPIO_RX_SCI_ROUTE;
+ Status = GpioReadWritePadCfgReg (
+ GpioPad,
+ 0,
+ B_PCH_GPIO_RX_SCI_ROUTE,
+ TRUE,
+ &Value
+ );
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
+
+/**
+ This procedure will set GPIO Input Rout SMI
+
+ @param[in] GpioPad GPIO pad
+ @param[in] Value Value for GPIRoutSMI
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or pad number
+**/
+EFI_STATUS
+GpioSetGpiRoutSmi (
+ IN GPIO_PAD GpioPad,
+ IN UINT32 Value
+ )
+{
+ EFI_STATUS Status;
+
+ Value <<= N_PCH_GPIO_RX_SMI_ROUTE;
+ Status = GpioReadWritePadCfgReg (
+ GpioPad,
+ 0,
+ B_PCH_GPIO_RX_SMI_ROUTE,
+ TRUE,
+ &Value
+ );
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
+
+/**
+ This procedure will set GPI SMI Enable setting for selected pad
+
+ @param[in] GpioPad GPIO pad
+ @param[in] PadGpiSmiEn GPI SMI Enable setting for selected pad
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or pad number
+**/
+EFI_STATUS
+GpioSetGpiSmiPadEn (
+ IN GPIO_PAD GpioPad,
+ IN UINT32 PadGpiSmiEn
+ )
+{
+ GPIO_GROUP Group;
+ GPIO_GROUP GpioGroupOffset;
+ UINT32 NumberOfGroups;
+ EFI_STATUS Status;
+
+ GpioGroupOffset = GpioGetLowestGroup ();
+ NumberOfGroups = GpioGetNumberOfGroups ();
+
+ Group = GpioGetGroupFromGpioPad (GpioPad);
+
+ //
+ // Check if group argument exceeds GPIO group range
+ //
+ if ((Group < GpioGroupOffset) || (Group >= NumberOfGroups + GpioGroupOffset)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = GpioReadWriteReg (
+ GpioSmiEnableRegister,
+ Group,
+ 0,
+ GpioPad,
+ TRUE,
+ TRUE,
+ &PadGpiSmiEn
+ );
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
+
+/**
+ This procedure will set GPI General Purpose Event Enable setting for selected pad
+
+ @param[in] GpioPad GPIO pad
+ @param[in] PadGpiGpeEn GPI General Purpose Event Enable setting for selected pad
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or pad number
+**/
+EFI_STATUS
+GpioSetGpiGpePadEn (
+ IN GPIO_PAD GpioPad,
+ IN UINT32 PadGpiGpeEn
+ )
+{
+ GPIO_GROUP Group;
+ GPIO_GROUP GpioGroupOffset;
+ UINT32 NumberOfGroups;
+ EFI_STATUS Status;
+
+ GpioGroupOffset = GpioGetLowestGroup ();
+ NumberOfGroups = GpioGetNumberOfGroups ();
+
+ Group = GpioGetGroupFromGpioPad (GpioPad);
+
+ //
+ // Check if group argument exceeds GPIO group range
+ //
+ if ((Group < GpioGroupOffset) || (Group >= NumberOfGroups + GpioGroupOffset)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+
+ Status = GpioReadWriteReg (
+ GpioGpeEnableRegister,
+ Group,
+ 0,
+ GpioPad,
+ TRUE,
+ TRUE,
+ &PadGpiGpeEn
+ );
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
+
+/**
+ Check if given GPIO Pad is locked
+
+ @param[in] GroupIndex GPIO group index
+ @param[in] PadNumber GPIO pad number
+
+ @retval TRUE Pad is locked
+ @retval FALSE Pad is not locked
+**/
+BOOLEAN
+GpioIsPadLocked (
+ IN UINT32 GroupIndex,
+ IN GPIO_PAD PadNumber
+ )
+{
+ UINT32 RegVal;
+ GPIO_GROUP_INFO *GpioGroupInfo;
+ UINTN GpioGroupInfoLength;
+
+ GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
+
+ // Read PADCFGLOCK register
+ //
+ RegVal = MmioRead32 ((UINTN)PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, GpioGroupInfo[GroupIndex].PadCfgLockOffset));
+
+ return (((RegVal >> PadNumber) & 0x1) == 1);
+}
+
+/**
+ Locks multiple GPIO pads using GPIO_INIT_CONFIG array.
+ Only locking is applied and no other GPIO pad configuration is changed.
+
+ @param[in] NumberOfItems Number of GPIO pads to be locked
+ @param[in] GpioInitTableAddress GPIO initialization table
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Invalid group or pad number
+ @retval EFI_UNSUPPORTED Incorrect GPIO pad definition
+**/
+static
+EFI_STATUS
+GpioLockPads (
+ IN UINT32 NumberOfItems,
+ IN GPIO_INIT_CONFIG *GpioInitTableAddress
+ )
+{
+ UINT32 Index;
+ UINT32 PadsToLock[V_PCH_GPIO_GROUP_MAX];
+ UINT32 PadsToLockTx[V_PCH_GPIO_GROUP_MAX];
+ GPIO_GROUP_INFO *GpioGroupInfo;
+ UINTN GpioGroupInfoLength;
+ GPIO_GROUP GpioGroupOffset;
+ UINT32 NumberOfGroups;
+ GPIO_PAD_OWN PadOwnVal;
+ GPIO_INIT_CONFIG *GpioData;
+ GPIO_GROUP Group;
+ UINT32 GroupIndex;
+ UINT32 PadNumber;
+ PCH_SERIES PchSeries;
+
+ PchSeries = GetPchSeries ();
+ PadOwnVal = GpioPadOwnHost;
+
+ ZeroMem (PadsToLock, sizeof (PadsToLock));
+ ZeroMem (PadsToLockTx, sizeof (PadsToLockTx));
+
+ GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
+
+ GpioGroupOffset = GpioGetLowestGroup ();
+ NumberOfGroups = GpioGetNumberOfGroups ();
+
+ for (Index = 0; Index < NumberOfItems; Index ++) {
+
+ GpioData = &GpioInitTableAddress[Index];
+
+ Group = GpioGetGroupFromGpioPad (GpioData->GpioPad);
+ GroupIndex = GpioGetGroupIndexFromGpioPad (GpioData->GpioPad);
+ PadNumber = GpioGetPadNumberFromGpioPad (GpioData->GpioPad);
+
+ //
+ // Checking GroupIndex to avoid Buffer Overflows or Array Out of Index
+ //
+ if (GroupIndex >= V_PCH_GPIO_GROUP_MAX) {
+ ASSERT (FALSE);
+ continue;
+ }
+
+ //
+ // Check if group argument exceeds GPIO group range
+ //
+ if ((Group < GpioGroupOffset) || (Group >= NumberOfGroups + GpioGroupOffset)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check if legal pin number
+ //
+ if (PadNumber >= GpioGroupInfo[GroupIndex].PadPerGroup){
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check if selected GPIO Pad is not owned by CSME/ISH
+ //
+ GpioGetPadOwnership (GpioData->GpioPad, &PadOwnVal);
+
+ if (PadOwnVal != GpioPadOwnHost) {
+ continue;
+ }
+
+ //
+ // Update information on Pad Configuration Lock
+ //
+ PadsToLock[GroupIndex] |= ((GpioData->GpioConfig.LockConfig >> 0x1) & 0x1) << PadNumber;
+
+ //
+ // Update information on Pad Configuration Lock Tx
+ //
+ PadsToLockTx[GroupIndex] |= ((GpioData->GpioConfig.LockConfig >> 0x2) & 0x1) << PadNumber;
+ }
+
+ for (Index = 0; Index < NumberOfGroups; Index++) {
+ //
+ // Write Pad Configuration Lock
+ //
+ if (PadsToLock[Index] != 0) {
+ GpioLockPadCfgForGroupDw (Index + GpioGroupOffset, 0, PadsToLock[Index]);
+ }
+
+ //
+ // Write Pad Configuration Lock Tx
+ //
+ if (PadsToLockTx[Index] != 0) {
+ GpioLockPadCfgTxForGroupDw (Index + GpioGroupOffset, 0, PadsToLockTx[Index]);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Locks GPIO pads according to GPIO_INIT_CONFIG array from
+ gPlatformGpioConfigGuid HOB. Only locking is applied and no other GPIO pad
+ configuration is changed.
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_NOT_FOUND gPlatformGpioConfigGuid not found
+**/
+EFI_STATUS
+GpioLockGpios (
+ VOID
+ )
+{
+ EFI_HOB_GUID_TYPE *GpioConfigHob;
+ GPIO_INIT_CONFIG *GpioConfig;
+ UINT16 GpioConfigSize;
+
+ GpioConfigHob = GetFirstGuidHob (&gPlatformGpioConfigGuid);
+ if (GpioConfigHob == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ ASSERT (GET_GUID_HOB_DATA_SIZE (GpioConfigHob) % sizeof (GpioConfig[0]) == 0);
+ GpioConfigSize = GET_GUID_HOB_DATA_SIZE (GpioConfigHob) / sizeof (GpioConfig[0]);
+ GpioConfig = GET_GUID_HOB_DATA (GpioConfigHob);
+ GpioLockPads (GpioConfigSize, GpioConfig);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Unlocks all PCH GPIO pads
+
+ @retval None
+**/
+VOID
+GpioUnlockAllGpios (
+ VOID
+ )
+{
+ GPIO_GROUP GpioGroupOffset;
+ UINT32 NumberOfGroups;
+ UINT32 Index;
+
+ GpioGroupOffset = GpioGetLowestGroup ();
+ NumberOfGroups = GpioGetNumberOfGroups ();
+
+ for (Index = 0; Index < NumberOfGroups; Index++) {
+ //
+ // Reset Pad Configuration Lock
+ //
+ GpioUnlockPadCfgForGroupDw (Index + GpioGroupOffset, 0, 0xFFFFFFFF);
+
+ //
+ // Reset Pad Configuration Lock Tx
+ //
+ GpioUnlockPadCfgTxForGroupDw (Index + GpioGroupOffset, 0, 0xFFFFFFFF);
+ }
+}
+