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