/** @file
This file contains GPIO routines for RC usage
Copyright (c) 2017, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/**
This procedure will get value of selected gpio register
@param[in] Group GPIO group number
@param[in] Offset GPIO register offset
@param[out] RegVal Value of gpio register
@retval EFI_SUCCESS The function completed successfully
@retval EFI_INVALID_PARAMETER Invalid group or pad number
**/
EFI_STATUS
GpioGetReg (
IN GPIO_GROUP Group,
IN UINT32 Offset,
OUT UINT32 *RegVal
)
{
GPIO_GROUP_INFO *GpioGroupInfo;
UINTN GpioGroupInfoLength;
UINTN GroupIndex;
GroupIndex = GpioGetGroupIndexFromGroup (Group);
GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
//
// Check if group argument exceeds GPIO GROUP INFO array
//
if ((UINTN) GroupIndex >= GpioGroupInfoLength) {
ASSERT (FALSE);
return EFI_INVALID_PARAMETER;
}
*RegVal = MmioRead32 (PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, Offset));
return EFI_SUCCESS;
}
/**
This procedure will set value of selected gpio register
@param[in] Group GPIO group number
@param[in] Offset GPIO register offset
@param[in] RegVal Value of gpio register
@retval EFI_SUCCESS The function completed successfully
@retval EFI_INVALID_PARAMETER Invalid group or pad number
**/
EFI_STATUS
GpioSetReg (
IN GPIO_GROUP Group,
IN UINT32 Offset,
IN UINT32 RegVal
)
{
GPIO_GROUP_INFO *GpioGroupInfo;
UINTN GpioGroupInfoLength;
UINTN GroupIndex;
GroupIndex = GpioGetGroupIndexFromGroup (Group);
GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
//
// Check if group argument exceeds GPIO GROUP INFO array
//
if ((UINTN) GroupIndex >= GpioGroupInfoLength) {
ASSERT (FALSE);
return EFI_INVALID_PARAMETER;
}
MmioWrite32 (PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, Offset), RegVal);
return EFI_SUCCESS;
}
/**
This procedure is used by PchSmiDispatcher and will return information
needed to register GPI SMI. Relation between Index and GpioPad number is:
Index = GpioGroup + 24 * GpioPad
@param[in] Index GPI SMI number
@param[out] GpioPin GPIO pin
@param[out] GpiSmiBitOffset GPI SMI bit position within GpiSmi Registers
@param[out] GpiSmiEnRegAddress Address of GPI SMI Enable register
@param[out] GpiSmiStsRegAddress Address of GPI SMI status register
@retval EFI_SUCCESS The function completed successfully
@retval EFI_INVALID_PARAMETER Invalid group or pad number
**/
EFI_STATUS
GpioGetPadAndSmiRegs (
IN UINT32 Index,
OUT GPIO_PAD *GpioPin,
OUT UINT8 *GpiSmiBitOffset,
OUT UINT32 *GpiSmiEnRegAddress,
OUT UINT32 *GpiSmiStsRegAddress
)
{
UINT32 GroupIndex;
UINT32 PadNumber;
GPIO_GROUP_INFO *GpioGroupInfo;
GPIO_GROUP GpioGroupOffset;
UINTN GpioGroupInfoLength;
UINT32 SmiRegOffset;
GPIO_PAD_OWN PadOwnVal;
UINT32 HostOwnVal;
GpioGroupInfo = GpioGetGroupInfoTable (&GpioGroupInfoLength);
GpioGroupOffset = GpioGetLowestGroup ();
PadNumber = 0;
GroupIndex = 0;
for (GroupIndex = 0; GroupIndex < GpioGroupInfoLength; GroupIndex++) {
PadNumber = Index;
if (PadNumber < GpioGroupInfo[GroupIndex].PadPerGroup) {
//
// Found group and pad number
//
break;
}
Index = Index - GpioGroupInfo[GroupIndex].PadPerGroup;
}
//
// Check if legal pad number
//
if (PadNumber >= GpioGroupInfo[GroupIndex].PadPerGroup){
return EFI_INVALID_PARAMETER;
}
//
// Check if selected group has GPI SMI Enable and Status registers
//
if (GpioGroupInfo[GroupIndex].SmiEnOffset == NO_REGISTER_FOR_PROPERTY) {
return EFI_INVALID_PARAMETER;
}
DEBUG_CODE_BEGIN ();
//
// Check if selected GPIO Pad is not owned by CSME/ISH/IE
//
GpioGetPadOwnership (GpioGetGpioPadFromGroupAndPadNumber (GroupIndex + GpioGroupOffset, PadNumber), &PadOwnVal);
if (PadOwnVal != GpioPadOwnHost) {
DEBUG ((DEBUG_ERROR, "GPIO ERROR: Accessing pad not owned by host (Group=%d, Pad=%d)!\n",GroupIndex, PadNumber));
return EFI_INVALID_PARAMETER;
}
//
// Check if Host Software Pad Ownership is set to ACPI Mode
//
GpioGetHostSwOwnershipForPad (GpioGetGpioPadFromGroupAndPadNumber (GroupIndex + GpioGroupOffset, PadNumber), &HostOwnVal);
if (HostOwnVal != V_PCH_PCR_GPIO_HOSTSW_OWN_ACPI) {
ASSERT (FALSE);
return EFI_INVALID_PARAMETER;
}
DEBUG_CODE_END ();
*GpioPin = GpioGetGpioPadFromGroupAndPadNumber (GroupIndex + GpioGroupOffset, PadNumber);
*GpiSmiBitOffset = (UINT8)(PadNumber % 32);
SmiRegOffset = GpioGroupInfo[GroupIndex].SmiEnOffset + (PadNumber / 32) * 0x4;
*GpiSmiEnRegAddress = PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, SmiRegOffset);
SmiRegOffset = GpioGroupInfo[GroupIndex].SmiStsOffset + (PadNumber / 32) * 0x4;
*GpiSmiStsRegAddress = PCH_PCR_ADDRESS (GpioGroupInfo[GroupIndex].Community, SmiRegOffset);
return EFI_SUCCESS;
}
/**
This procedure will clear GPIO_UNLOCK_SMI_STS
@param[in] None
@retval EFI_SUCCESS The function completed successfully
@retval EFI_INVALID_PARAMETER Invalid group or pad number
**/
EFI_STATUS
GpioClearUnlockSmiSts (
VOID
)
{
UINT16 AcpiBaseAddr;
PchAcpiBaseGet (&AcpiBaseAddr);
//
// GPIO_UNLOCK_SMI_STS is cleared by writing 1 to it. Other bits in
// R_PCH_SMI_STS registers are either RO or RW/1C so writing 0 to them
// will not change their state.
//
IoWrite32 (AcpiBaseAddr + R_PCH_SMI_STS, B_PCH_SMI_STS_GPIO_UNLOCK);
return EFI_SUCCESS;
}
/**
This procedure will set GPIO Driver IRQ number
@param[in] Irq Irq number
@retval EFI_SUCCESS The function completed successfully
@retval EFI_INVALID_PARAMETER Invalid IRQ number
**/
EFI_STATUS
GpioSetIrq (
IN UINT8 Irq
)
{
UINT32 Data32And;
UINT32 Data32Or;
//
// Check if Irq is 14 or 15
//
if ((Irq < 14) || (Irq > 15)) {
ASSERT (FALSE);
return EFI_INVALID_PARAMETER;
}
Data32And = (UINT32) ~(B_PCH_PCR_GPIO_MISCCFG_IRQ_ROUTE);
Data32Or = (UINT32) (Irq - 14) << N_PCH_PCR_GPIO_MISCCFG_IRQ_ROUTE;
//
// Program MISCCFG register for Community 0
//
MmioAndThenOr32 (
PCH_PCR_ADDRESS (PID_GPIOCOM0, R_PCH_PCR_GPIO_MISCCFG),
Data32And,
Data32Or
);
//
// Program MISCCFG register for Community 1
//
MmioAndThenOr32 (
PCH_PCR_ADDRESS (PID_GPIOCOM1, R_PCH_PCR_GPIO_MISCCFG),
Data32And,
Data32Or
);
//
// Program MISCCFG register for Community 2
//
MmioAndThenOr32 (
PCH_PCR_ADDRESS (PID_GPIOCOM2, R_PCH_PCR_GPIO_MISCCFG),
Data32And,
Data32Or
);
//
// Program MISCCFG register for Community 3
//
MmioAndThenOr32 (
PCH_PCR_ADDRESS (PID_GPIOCOM3, R_PCH_PCR_GPIO_MISCCFG),
Data32And,
Data32Or
);
return EFI_SUCCESS;
}
/**
This procedure will perform special handling of GPP_A_12 on PCH-LP.
@param[in] None
@retval None
**/
VOID
GpioA12SpecialHandling (
VOID
)
{
GPIO_PAD_OWN PadOwnVal;
//
// SKL PCH BWG 16.6. PCH-LP GPP_A_12 Special Handling
//
if (GetPchSeries () == PchLp) {
GpioGetPadOwnership (GPIO_SKL_LP_GPP_A12, &PadOwnVal);
//
// If the pad is host-own, BIOS has to always lock this pad after being initialized
//
if (PadOwnVal == GpioPadOwnHost) {
//
// Set PadCfgLock for GPP_A_12
//
GpioLockPadCfg (GPIO_SKL_LP_GPP_A12);
}
}
}