diff --git a/ArmPlatformPkg/Drivers/PL061GpioDxe/PL061Gpio.c b/ArmPlatformPkg/Drivers/PL061GpioDxe/PL061Gpio.c index 38341a3d05..0e2ea61ce8 100644 --- a/ArmPlatformPkg/Drivers/PL061GpioDxe/PL061Gpio.c +++ b/ArmPlatformPkg/Drivers/PL061GpioDxe/PL061Gpio.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -28,6 +29,33 @@ #include #include +PLATFORM_GPIO_CONTROLLER *mPL061PlatformGpio; + +EFI_STATUS +EFIAPI +PL061Locate ( + IN EMBEDDED_GPIO_PIN Gpio, + OUT UINTN *ControllerIndex, + OUT UINTN *ControllerOffset, + OUT UINTN *RegisterBase + ) +{ + UINT32 Index; + + for (Index = 0; Index < mPL061PlatformGpio->GpioControllerCount; Index++) { + if ( (Gpio >= mPL061PlatformGpio->GpioController[Index].GpioIndex) + && (Gpio < mPL061PlatformGpio->GpioController[Index].GpioIndex + + mPL061PlatformGpio->GpioController[Index].InternalGpioCount)) { + *ControllerIndex = Index; + *ControllerOffset = Gpio % mPL061PlatformGpio->GpioController[Index].InternalGpioCount; + *RegisterBase = mPL061PlatformGpio->GpioController[Index].RegisterBase; + return EFI_SUCCESS; + } + } + DEBUG ((EFI_D_ERROR, "%a, failed to locate gpio %d\n", __func__, Gpio)); + return EFI_INVALID_PARAMETER; +} + // // The PL061 is a strange beast. The 8-bit data register is aliased across a // region 0x400 bytes in size, with bits [9:2] of the address operating as a @@ -88,20 +116,36 @@ PL061Identify ( VOID ) { - // Check if this is a PrimeCell Peripheral - if ( (MmioRead8 (PL061_GPIO_PCELL_ID0) != 0x0D) - || (MmioRead8 (PL061_GPIO_PCELL_ID1) != 0xF0) - || (MmioRead8 (PL061_GPIO_PCELL_ID2) != 0x05) - || (MmioRead8 (PL061_GPIO_PCELL_ID3) != 0xB1)) { - return EFI_NOT_FOUND; + UINTN Index; + UINTN RegisterBase; + + if ( (mPL061PlatformGpio->GpioCount == 0) + || (mPL061PlatformGpio->GpioControllerCount == 0)) { + return EFI_NOT_FOUND; } - // Check if this PrimeCell Peripheral is the PL061 GPIO - if ( (MmioRead8 (PL061_GPIO_PERIPH_ID0) != 0x61) - || (MmioRead8 (PL061_GPIO_PERIPH_ID1) != 0x10) - || ((MmioRead8 (PL061_GPIO_PERIPH_ID2) & 0xF) != 0x04) - || (MmioRead8 (PL061_GPIO_PERIPH_ID3) != 0x00)) { - return EFI_NOT_FOUND; + for (Index = 0; Index < mPL061PlatformGpio->GpioControllerCount; Index++) { + if (mPL061PlatformGpio->GpioController[Index].InternalGpioCount != PL061_GPIO_PINS) { + return EFI_INVALID_PARAMETER; + } + + RegisterBase = mPL061PlatformGpio->GpioController[Index].RegisterBase; + + // Check if this is a PrimeCell Peripheral + if ( (MmioRead8 (RegisterBase + PL061_GPIO_PCELL_ID0) != 0x0D) + || (MmioRead8 (RegisterBase + PL061_GPIO_PCELL_ID1) != 0xF0) + || (MmioRead8 (RegisterBase + PL061_GPIO_PCELL_ID2) != 0x05) + || (MmioRead8 (RegisterBase + PL061_GPIO_PCELL_ID3) != 0xB1)) { + return EFI_NOT_FOUND; + } + + // Check if this PrimeCell Peripheral is the PL061 GPIO + if ( (MmioRead8 (RegisterBase + PL061_GPIO_PERIPH_ID0) != 0x61) + || (MmioRead8 (RegisterBase + PL061_GPIO_PERIPH_ID1) != 0x10) + || ((MmioRead8 (RegisterBase + PL061_GPIO_PERIPH_ID2) & 0xF) != 0x04) + || (MmioRead8 (RegisterBase + PL061_GPIO_PERIPH_ID3) != 0x00)) { + return EFI_NOT_FOUND; + } } return EFI_SUCCESS; @@ -132,13 +176,17 @@ Get ( OUT UINTN *Value ) { - if ( (Value == NULL) - || (Gpio > LAST_GPIO_PIN)) - { + EFI_STATUS Status = EFI_SUCCESS; + UINTN Index, Offset, RegisterBase; + + Status = PL061Locate (Gpio, &Index, &Offset, &RegisterBase); + ASSERT_EFI_ERROR (Status); + + if (Value == NULL) { return EFI_INVALID_PARAMETER; } - if (PL061GetPins (PL061_GPIO_DATA_REG, Gpio)) { + if (PL061GetPins (RegisterBase + PL061_GPIO_DATA_REG, Offset)) { *Value = 1; } else { *Value = 0; @@ -174,41 +222,39 @@ Set ( ) { EFI_STATUS Status = EFI_SUCCESS; + UINTN Index, Offset, RegisterBase; - // Check for errors - if (Gpio > LAST_GPIO_PIN) { - Status = EFI_INVALID_PARAMETER; - goto EXIT; - } + Status = PL061Locate (Gpio, &Index, &Offset, &RegisterBase); + ASSERT_EFI_ERROR (Status); switch (Mode) { case GPIO_MODE_INPUT: // Set the corresponding direction bit to LOW for input - MmioAnd8 (PL061_GPIO_DIR_REG, ~GPIO_PIN_MASK(Gpio) & 0xFF); + MmioAnd8 (RegisterBase + PL061_GPIO_DIR_REG, + ~GPIO_PIN_MASK(Offset) & 0xFF); break; case GPIO_MODE_OUTPUT_0: // Set the corresponding direction bit to HIGH for output - MmioOr8 (PL061_GPIO_DIR_REG, GPIO_PIN_MASK(Gpio)); + MmioOr8 (RegisterBase + PL061_GPIO_DIR_REG, GPIO_PIN_MASK(Offset)); // Set the corresponding data bit to LOW for 0 - PL061SetPins (PL061_GPIO_DATA_REG, GPIO_PIN_MASK(Gpio), 0); + PL061SetPins (RegisterBase + PL061_GPIO_DATA_REG, GPIO_PIN_MASK(Offset), 0); break; case GPIO_MODE_OUTPUT_1: // Set the corresponding direction bit to HIGH for output - MmioOr8 (PL061_GPIO_DIR_REG, GPIO_PIN_MASK(Gpio)); + MmioOr8 (RegisterBase + PL061_GPIO_DIR_REG, GPIO_PIN_MASK(Offset)); // Set the corresponding data bit to HIGH for 1 - PL061SetPins (PL061_GPIO_DATA_REG, GPIO_PIN_MASK(Gpio), 0xff); - break; + PL061SetPins (RegisterBase + PL061_GPIO_DATA_REG, GPIO_PIN_MASK(Offset), 0xff); + break; default: // Other modes are not supported return EFI_UNSUPPORTED; } -EXIT: - return Status; + return EFI_SUCCESS; } /** @@ -237,16 +283,21 @@ GetMode ( OUT EMBEDDED_GPIO_MODE *Mode ) { + EFI_STATUS Status = EFI_SUCCESS; + UINTN Index, Offset, RegisterBase; + + Status = PL061Locate (Gpio, &Index, &Offset, &RegisterBase); + ASSERT_EFI_ERROR (Status); + // Check for errors - if ( (Mode == NULL) - || (Gpio > LAST_GPIO_PIN)) { + if (Mode == NULL) { return EFI_INVALID_PARAMETER; } // Check if it is input or output - if (MmioRead8 (PL061_GPIO_DIR_REG) & GPIO_PIN_MASK(Gpio)) { + if (MmioRead8 (RegisterBase + PL061_GPIO_DIR_REG) & GPIO_PIN_MASK(Offset)) { // Pin set to output - if (PL061GetPins (PL061_GPIO_DATA_REG, GPIO_PIN_MASK(Gpio))) { + if (PL061GetPins (RegisterBase + PL061_GPIO_DATA_REG, GPIO_PIN_MASK(Offset))) { *Mode = GPIO_MODE_OUTPUT_1; } else { *Mode = GPIO_MODE_OUTPUT_0; @@ -315,14 +366,34 @@ PL061InstallProtocol ( IN EFI_SYSTEM_TABLE *SystemTable ) { - EFI_STATUS Status; - EFI_HANDLE Handle; + EFI_STATUS Status; + EFI_HANDLE Handle; + GPIO_CONTROLLER *GpioController; // // Make sure the Gpio protocol has not been installed in the system yet. // ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEmbeddedGpioProtocolGuid); + Status = gBS->LocateProtocol (&gPlatformGpioProtocolGuid, NULL, (VOID **)&mPL061PlatformGpio); + if (EFI_ERROR (Status) && (Status == EFI_NOT_FOUND)) { + // Create the mPL061PlatformGpio + mPL061PlatformGpio = (PLATFORM_GPIO_CONTROLLER *)AllocateZeroPool (sizeof (PLATFORM_GPIO_CONTROLLER) + sizeof (GPIO_CONTROLLER)); + if (mPL061PlatformGpio == NULL) { + DEBUG ((EFI_D_ERROR, "%a: failed to allocate PLATFORM_GPIO_CONTROLLER\n", __func__)); + return EFI_BAD_BUFFER_SIZE; + } + + mPL061PlatformGpio->GpioCount = PL061_GPIO_PINS; + mPL061PlatformGpio->GpioControllerCount = 1; + mPL061PlatformGpio->GpioController = (GPIO_CONTROLLER *)((UINTN) mPL061PlatformGpio + sizeof (PLATFORM_GPIO_CONTROLLER)); + + GpioController = mPL061PlatformGpio->GpioController; + GpioController->RegisterBase = (UINTN) PcdGet32 (PcdPL061GpioBase); + GpioController->GpioIndex = 0; + GpioController->InternalGpioCount = PL061_GPIO_PINS; + } + Status = PL061Identify(); if (EFI_ERROR(Status)) { return EFI_DEVICE_ERROR; diff --git a/ArmPlatformPkg/Drivers/PL061GpioDxe/PL061GpioDxe.inf b/ArmPlatformPkg/Drivers/PL061GpioDxe/PL061GpioDxe.inf index 9d9e4cd678..405a3a9994 100644 --- a/ArmPlatformPkg/Drivers/PL061GpioDxe/PL061GpioDxe.inf +++ b/ArmPlatformPkg/Drivers/PL061GpioDxe/PL061GpioDxe.inf @@ -45,6 +45,7 @@ [Protocols] gEmbeddedGpioProtocolGuid + gPlatformGpioProtocolGuid [Depex] TRUE diff --git a/ArmPlatformPkg/Include/Drivers/PL061Gpio.h b/ArmPlatformPkg/Include/Drivers/PL061Gpio.h index 8fde2bb5ef..308f69fa84 100644 --- a/ArmPlatformPkg/Include/Drivers/PL061Gpio.h +++ b/ArmPlatformPkg/Include/Drivers/PL061Gpio.h @@ -20,30 +20,28 @@ // PL061 GPIO Registers #define PL061_GPIO_DATA_REG_OFFSET ((UINTN) 0x000) -#define PL061_GPIO_DATA_REG ((UINT32)PcdGet32 (PcdPL061GpioBase) + 0x000) -#define PL061_GPIO_DIR_REG ((UINT32)PcdGet32 (PcdPL061GpioBase) + 0x400) -#define PL061_GPIO_IS_REG ((UINT32)PcdGet32 (PcdPL061GpioBase) + 0x404) -#define PL061_GPIO_IBE_REG ((UINT32)PcdGet32 (PcdPL061GpioBase) + 0x408) -#define PL061_GPIO_IEV_REG ((UINT32)PcdGet32 (PcdPL061GpioBase) + 0x40C) -#define PL061_GPIO_IE_REG ((UINT32)PcdGet32 (PcdPL061GpioBase) + 0x410) -#define PL061_GPIO_RIS_REG ((UINT32)PcdGet32 (PcdPL061GpioBase) + 0x414) -#define PL061_GPIO_MIS_REG ((UINT32)PcdGet32 (PcdPL061GpioBase) + 0x410) -#define PL061_GPIO_IC_REG ((UINT32)PcdGet32 (PcdPL061GpioBase) + 0x41C) -#define PL061_GPIO_AFSEL_REG ((UINT32)PcdGet32 (PcdPL061GpioBase) + 0x420) +#define PL061_GPIO_DATA_REG 0x000 +#define PL061_GPIO_DIR_REG 0x400 +#define PL061_GPIO_IS_REG 0x404 +#define PL061_GPIO_IBE_REG 0x408 +#define PL061_GPIO_IEV_REG 0x40C +#define PL061_GPIO_IE_REG 0x410 +#define PL061_GPIO_RIS_REG 0x414 +#define PL061_GPIO_MIS_REG 0x410 +#define PL061_GPIO_IC_REG 0x41C +#define PL061_GPIO_AFSEL_REG 0x420 -#define PL061_GPIO_PERIPH_ID0 ((UINT32)PcdGet32 (PcdPL061GpioBase) + 0xFE0) -#define PL061_GPIO_PERIPH_ID1 ((UINT32)PcdGet32 (PcdPL061GpioBase) + 0xFE4) -#define PL061_GPIO_PERIPH_ID2 ((UINT32)PcdGet32 (PcdPL061GpioBase) + 0xFE8) -#define PL061_GPIO_PERIPH_ID3 ((UINT32)PcdGet32 (PcdPL061GpioBase) + 0xFEC) +#define PL061_GPIO_PERIPH_ID0 0xFE0 +#define PL061_GPIO_PERIPH_ID1 0xFE4 +#define PL061_GPIO_PERIPH_ID2 0xFE8 +#define PL061_GPIO_PERIPH_ID3 0xFEC -#define PL061_GPIO_PCELL_ID0 ((UINT32)PcdGet32 (PcdPL061GpioBase) + 0xFF0) -#define PL061_GPIO_PCELL_ID1 ((UINT32)PcdGet32 (PcdPL061GpioBase) + 0xFF4) -#define PL061_GPIO_PCELL_ID2 ((UINT32)PcdGet32 (PcdPL061GpioBase) + 0xFF8) -#define PL061_GPIO_PCELL_ID3 ((UINT32)PcdGet32 (PcdPL061GpioBase) + 0xFFC) +#define PL061_GPIO_PCELL_ID0 0xFF0 +#define PL061_GPIO_PCELL_ID1 0xFF4 +#define PL061_GPIO_PCELL_ID2 0xFF8 +#define PL061_GPIO_PCELL_ID3 0xFFC - -// GPIO pins are numbered 0..7 -#define LAST_GPIO_PIN 7 +#define PL061_GPIO_PINS 8 // All bits low except one bit high, native bit length #define GPIO_PIN_MASK(Pin) (1UL << ((UINTN)(Pin)))