From: Vu Nguyen <vungu...@os.amperecomputing.com> The DwGpioLib library provides basic functions to control the GPIO controller on Ampere Altra processor.
Cc: Thang Nguyen <th...@os.amperecomputing.com> Cc: Chuong Tran <chu...@os.amperecomputing.com> Cc: Phong Vo <ph...@os.amperecomputing.com> Cc: Leif Lindholm <l...@nuviainc.com> Cc: Michael D Kinney <michael.d.kin...@intel.com> Cc: Ard Biesheuvel <ardb+tianoc...@kernel.org> Cc: Nate DeSimone <nathaniel.l.desim...@intel.com> Signed-off-by: Vu Nguyen <vungu...@os.amperecomputing.com> Reviewed-by: Leif Lindholm <l...@nuviainc.com> --- Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec | 3 + Silicon/Ampere/AmpereAltraPkg/Library/DwGpioLib/DwGpioLib.inf | 33 ++ Silicon/Ampere/AmpereAltraPkg/Include/Library/GpioLib.h | 76 +++++ Silicon/Ampere/AmpereAltraPkg/Library/DwGpioLib/DwGpioLib.c | 314 ++++++++++++++++++++ 4 files changed, 426 insertions(+) diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec index 8be6a329bb26..be827dd19a96 100644 --- a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec +++ b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec @@ -31,6 +31,9 @@ [LibraryClasses] ## @libraryclass Defines a set of methods to read/write to I2C devices. I2cLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/I2cLib.h + ## @libraryclass Defines a set of methods to get/set GPIO. + GpioLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/GpioLib.h + ## @libraryclass Defines a set of methods to communicate with secure parition over MM interface. MmCommunicationLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/MmCommunicationLib.h diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/DwGpioLib/DwGpioLib.inf b/Silicon/Ampere/AmpereAltraPkg/Library/DwGpioLib/DwGpioLib.inf new file mode 100644 index 000000000000..36ce0c3be2c8 --- /dev/null +++ b/Silicon/Ampere/AmpereAltraPkg/Library/DwGpioLib/DwGpioLib.inf @@ -0,0 +1,33 @@ +## @file +# Component description for DwGpioLib library for the Designware GPIO controller. +# +# Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x0001001B + BASE_NAME = DwGpioLib + FILE_GUID = E7D9CAE1-6930-46E3-BDF9-0027446E7DF2 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = GpioLib + +[Sources.common] + DwGpioLib.c + +[Packages] + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + MdePkg/MdePkg.dec + Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + IoLib + +[Guids] + gEfiEventVirtualAddressChangeGuid diff --git a/Silicon/Ampere/AmpereAltraPkg/Include/Library/GpioLib.h b/Silicon/Ampere/AmpereAltraPkg/Include/Library/GpioLib.h new file mode 100644 index 000000000000..cb201bc98322 --- /dev/null +++ b/Silicon/Ampere/AmpereAltraPkg/Include/Library/GpioLib.h @@ -0,0 +1,76 @@ +/** @file + Library implementation for the Designware GPIO controller. + + Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef GPIO_LIB_H_ +#define GPIO_LIB_H_ + +enum SocGpioConfigMode { + GPIO_CONFIG_OUT_LOW = 0, + GPIO_CONFIG_OUT_HI, + GPIO_CONFIG_OUT_LOW_TO_HIGH, + GPIO_CONFIG_OUT_HIGH_TO_LOW, + GPIO_CONFIG_IN, + MAX_GPIO_CONFIG_MODE +}; + +/* + * GpioWriteBit: Use to Set/Clear GPIOs + * Input: + * Pin : Pin Identification + * Val : 1 to Set, 0 to Clear + */ +VOID +EFIAPI +GpioWriteBit ( + IN UINT32 Pin, + IN UINT32 Val + ); + +/* + * GpioReadBit: + * Input: + * Pin : Pin Identification + * Return: + * 1 : On/High + * 0 : Off/Low + */ +UINTN +EFIAPI +GpioReadBit ( + IN UINT32 Pin + ); + +/* + * GpioModeConfig: Use to configure GPIOs as Input/Output + * Input: + * Pin : Pin Identification + * InOut : GPIO_OUT/1 as Output + * GPIO_IN/0 as Input + */ +EFI_STATUS +EFIAPI +GpioModeConfig ( + UINT8 Pin, + UINTN Mode + ); + +/* + * Setup a controller that to be used in runtime service. + * Input: + * Pin: Pin belongs to the controller. + * return: 0 for success. + * Otherwise, error code. + */ +EFI_STATUS +EFIAPI +GpioSetupRuntime ( + IN UINT32 Pin + ); + +#endif /* GPIO_LIB_H_ */ diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/DwGpioLib/DwGpioLib.c b/Silicon/Ampere/AmpereAltraPkg/Library/DwGpioLib/DwGpioLib.c new file mode 100644 index 000000000000..dbb53f7d57d2 --- /dev/null +++ b/Silicon/Ampere/AmpereAltraPkg/Library/DwGpioLib/DwGpioLib.c @@ -0,0 +1,314 @@ +/** @file + + Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiDxe.h> +#include <Uefi.h> + +#include <Library/DebugLib.h> +#include <Library/GpioLib.h> +#include <Library/DxeServicesTableLib.h> +#include <Library/IoLib.h> +#include <Library/TimerLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiRuntimeLib.h> +#include <Platform/Ac01.h> + +/* Runtime needs to be 64K alignment */ +#define RUNTIME_ADDRESS_MASK (~(SIZE_64KB - 1)) +#define RUNTIME_ADDRESS_LENGTH SIZE_64KB + +#define GPIO_MUX_VAL(Gpio) (0x00000001 << (Gpio)) +#define GPIO_IN 0 +#define GPIO_OUT 1 + +/* Address GPIO_REG Registers */ +#define GPIO_SWPORTA_DR_ADDR 0x00000000 +#define GPIO_SWPORTA_DDR_ADDR 0x00000004 +#define GPIO_EXT_PORTA_ADDR 0x00000050 + +STATIC UINT64 GpioBaseAddr[] = { GPIO_DWAPB_BASE_ADDR }; +STATIC UINT64 GpiBaseAddr[] = { GPI_DWAPB_BASE_ADDR }; +STATIC BOOLEAN GpioRuntimeEnableArray[sizeof (GpioBaseAddr) / sizeof (GpioBaseAddr[0])] = { FALSE }; +STATIC EFI_EVENT mVirtualAddressChangeEvent = NULL; + +UINT64 +GetBaseAddr ( + IN UINT32 Pin + ) +{ + UINT32 NumberOfControllers = sizeof (GpioBaseAddr) / sizeof (GpioBaseAddr[0]); + UINT32 TotalPins = GPIO_DWAPB_PINS_PER_CONTROLLER * NumberOfControllers; + + if (NumberOfControllers == 0 || Pin >= TotalPins) { + return 0; + } + + return GpioBaseAddr[Pin / GPIO_DWAPB_PINS_PER_CONTROLLER]; +} + +VOID +GpioWrite ( + IN UINT64 Base, + IN UINT32 Val + ) +{ + MmioWrite32 ((UINTN)Base, Val); +} + +VOID +GpioRead ( + IN UINT64 Base, + OUT UINT32 *Val + ) +{ + ASSERT (Val != NULL); + *Val = MmioRead32 (Base); +} + +VOID +EFIAPI +GpioWriteBit ( + IN UINT32 Pin, + IN UINT32 Val + ) +{ + UINT64 Reg; + UINT32 GpioPin; + UINT32 ReadVal; + + Reg = GetBaseAddr (Pin); + if (Reg == 0) { + return; + } + + GpioPin = Pin % GPIO_DWAPB_PINS_PER_CONTROLLER; + + Reg += GPIO_SWPORTA_DR_ADDR; + GpioRead (Reg, &ReadVal); + + if (Val != 0) { + GpioWrite (Reg, ReadVal | GPIO_MUX_VAL (GpioPin)); + } else { + GpioWrite (Reg, ReadVal & ~GPIO_MUX_VAL (GpioPin)); + } +} + +UINTN +EFIAPI +GpioReadBit ( + IN UINT32 Pin + ) +{ + UINT64 Reg; + UINT32 Val; + UINT32 GpioPin; + UINT8 Index; + UINT32 MaxIndex; + + Reg = GetBaseAddr (Pin); + if (Reg == 0) { + return 0; + } + + GpioPin = Pin % GPIO_DWAPB_PINS_PER_CONTROLLER; + + /* Check if a base address is GPI */ + MaxIndex = sizeof (GpiBaseAddr) / sizeof (GpiBaseAddr[0]); + for (Index = 0; Index < MaxIndex; Index++) { + if (Reg == GpiBaseAddr[Index]) { + break; + } + } + if (Index == MaxIndex) { + /* Only GPIO has GPIO_EXT_PORTA register, not for GPI */ + Reg += GPIO_EXT_PORTA_ADDR; + } + + GpioRead (Reg, &Val); + + return Val & GPIO_MUX_VAL (GpioPin) ? 1 : 0; +} + +EFI_STATUS +GpioConfig ( + IN UINT32 Pin, + IN UINT32 InOut + ) +{ + INTN GpioPin; + UINT32 Val; + UINT64 Reg; + + /* + * Caculate GPIO Pin Number for Direction Register + * GPIO_SWPORTA_DDR for GPIO[31...0] + * GPIO_SWPORTB_DDR for GPIO[51...32] + */ + + Reg = GetBaseAddr (Pin); + if (Reg == 0) { + return EFI_UNSUPPORTED; + } + + Reg += GPIO_SWPORTA_DDR_ADDR; + GpioPin = Pin % GPIO_DWAPB_PINS_PER_CONTROLLER; + GpioRead (Reg, &Val); + + if (InOut == GPIO_OUT) { + Val |= GPIO_MUX_VAL (GpioPin); + } else { + Val &= ~GPIO_MUX_VAL (GpioPin); + } + GpioWrite (Reg, Val); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +GpioModeConfig ( + UINT8 Pin, + UINTN Mode + ) +{ + UINT32 NumberOfControllers = sizeof (GpioBaseAddr) / sizeof (UINT64); + UINT32 NumersOfPins = NumberOfControllers * GPIO_DWAPB_PINS_PER_CONTROLLER; + UINT32 Delay = 10; + + if (Mode < GPIO_CONFIG_OUT_LOW + || Mode >= MAX_GPIO_CONFIG_MODE + || Pin > NumersOfPins - 1 + || Pin < 0) + { + return EFI_INVALID_PARAMETER; + } + + switch (Mode) { + case GPIO_CONFIG_OUT_LOW: + GpioConfig (Pin, GPIO_OUT); + GpioWriteBit (Pin, 0); + DEBUG ((DEBUG_INFO, "GPIO pin %d configured as output low\n", Pin)); + break; + + case GPIO_CONFIG_OUT_HI: + GpioConfig (Pin, GPIO_OUT); + GpioWriteBit (Pin, 1); + DEBUG ((DEBUG_INFO, "GPIO pin %d configured as output high\n", Pin)); + break; + + case GPIO_CONFIG_OUT_LOW_TO_HIGH: + GpioConfig (Pin, GPIO_OUT); + GpioWriteBit (Pin, 0); + MicroSecondDelay (1000 * Delay); + GpioWriteBit (Pin, 1); + DEBUG ((DEBUG_INFO, "GPIO pin %d configured as output low->high\n", Pin)); + break; + + case GPIO_CONFIG_OUT_HIGH_TO_LOW: + GpioConfig (Pin, GPIO_OUT); + GpioWriteBit (Pin, 1); + MicroSecondDelay (1000 * Delay); + GpioWriteBit (Pin, 0); + DEBUG ((DEBUG_INFO, "GPIO pin %d configured as output high->low\n", Pin)); + break; + + case GPIO_CONFIG_IN: + GpioConfig (Pin, GPIO_IN); + DEBUG ((DEBUG_INFO, "GPIO pin %d configured as input\n", Pin)); + break; + + default: + break; + } + + return EFI_SUCCESS; +} + +/** + * Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE. + * + * This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event. + * It convers pointer to new virtual address. + * + * @param Event Event whose notification function is being invoked. + * @param Context Pointer to the notification function's context. + */ +VOID +EFIAPI +GpioVirtualAddressChangeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + UINTN Count; + + EfiConvertPointer (0x0, (VOID **)&GpioBaseAddr); + for (Count = 0; Count < sizeof (GpioBaseAddr) / sizeof (GpioBaseAddr[0]); Count++) { + if (!GpioRuntimeEnableArray[Count]) { + continue; + } + EfiConvertPointer (0x0, (VOID **)&GpioBaseAddr[Count]); + } +} + +/** + Setup a controller that to be used in runtime service. + + @Bus: Bus ID. + @return: 0 for success. + Otherwise, error code. + **/ +EFI_STATUS +EFIAPI +GpioSetupRuntime ( + IN UINT32 Pin + ) +{ + EFI_STATUS Status; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor; + + if (GetBaseAddr (Pin) == 0) { + return EFI_INVALID_PARAMETER; + } + + if (mVirtualAddressChangeEvent == NULL) { + /* + * Register for the virtual address change event + */ + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + GpioVirtualAddressChangeEvent, + NULL, + &gEfiEventVirtualAddressChangeGuid, + &mVirtualAddressChangeEvent + ); + ASSERT_EFI_ERROR (Status); + } + + Status = gDS->GetMemorySpaceDescriptor ( + GetBaseAddr (Pin) & RUNTIME_ADDRESS_MASK, + &Descriptor + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gDS->SetMemorySpaceAttributes ( + GetBaseAddr (Pin) & RUNTIME_ADDRESS_MASK, + RUNTIME_ADDRESS_LENGTH, + Descriptor.Attributes | EFI_MEMORY_RUNTIME + ); + if (EFI_ERROR (Status)) { + return Status; + } + + GpioRuntimeEnableArray[Pin / GPIO_DWAPB_PINS_PER_CONTROLLER] = TRUE; + + return Status; +} -- 2.17.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#80707): https://edk2.groups.io/g/devel/message/80707 Mute This Topic: https://groups.io/mt/85631138/21656 Group Owner: devel+ow...@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-