diff mbox

[edk2,v5,2/2] ArmPlatformPkg: PL061: support multiple controller

Message ID BLU436-SMTP124DBDF4138A979D72F2F197880@phx.gbl
State Accepted
Commit 727894d5c90f0fc675848d7cc56513589e63a4b7
Headers show

Commit Message

Haojian Zhuang March 14, 2016, 5:30 a.m. UTC
Support multiple PL061 controllers. If platform gpio driver couldn't be
found, PL061 gpio driver will continue to load PcdPL061GpioBase as the
register base.

It could be compatible with the use case of current PL061 gpio driver.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>

---
 ArmPlatformPkg/Drivers/PL061GpioDxe/PL061Gpio.c    | 141 ++++++++++++++++-----
 .../Drivers/PL061GpioDxe/PL061GpioDxe.inf          |   1 +
 ArmPlatformPkg/Include/Drivers/PL061Gpio.h         |  46 ++++---
 3 files changed, 129 insertions(+), 59 deletions(-)

-- 
1.9.1

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Comments

Leif Lindholm March 14, 2016, 1:19 p.m. UTC | #1
On Mon, Mar 14, 2016 at 01:30:37PM +0800, Haojian Zhuang wrote:
> Support multiple PL061 controllers. If platform gpio driver couldn't be

> found, PL061 gpio driver will continue to load PcdPL061GpioBase as the

> register base.

> 

> It could be compatible with the use case of current PL061 gpio driver.


The content looks fine.
There are two whitespace errors, which are picked up by
BaseTools/Scripts/PatchCheck.py. Now, given that I've already been a
pain over this set, I don't mind fixing it up on commit, but it's
worth integrating this step into your workflow.

Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>

(Already pushed.)

> Contributed-under: TianoCore Contribution Agreement 1.0

> Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>

> ---

>  ArmPlatformPkg/Drivers/PL061GpioDxe/PL061Gpio.c    | 141 ++++++++++++++++-----

>  .../Drivers/PL061GpioDxe/PL061GpioDxe.inf          |   1 +

>  ArmPlatformPkg/Include/Drivers/PL061Gpio.h         |  46 ++++---

>  3 files changed, 129 insertions(+), 59 deletions(-)

> 

> diff --git a/ArmPlatformPkg/Drivers/PL061GpioDxe/PL061Gpio.c b/ArmPlatformPkg/Drivers/PL061GpioDxe/PL061Gpio.c

> index 38341a3..59d615d 100644

> --- a/ArmPlatformPkg/Drivers/PL061GpioDxe/PL061Gpio.c

> +++ b/ArmPlatformPkg/Drivers/PL061GpioDxe/PL061Gpio.c

> @@ -20,6 +20,7 @@

>  #include <Library/BaseMemoryLib.h>

>  #include <Library/DebugLib.h>

>  #include <Library/IoLib.h>

> +#include <Library/MemoryAllocationLib.h>

>  #include <Library/PcdLib.h>

>  #include <Library/UefiBootServicesTableLib.h>

>  #include <Library/UefiLib.h>

> @@ -28,6 +29,33 @@

>  #include <Protocol/EmbeddedGpio.h>

>  #include <Drivers/PL061Gpio.h>

>  

> +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 9d9e4cd..405a3a9 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 8fde2bb..308f69f 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_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_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)

> -

> -

> -// GPIO pins are numbered 0..7

> -#define LAST_GPIO_PIN                   7

> +#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           0xFE0

> +#define PL061_GPIO_PERIPH_ID1           0xFE4

> +#define PL061_GPIO_PERIPH_ID2           0xFE8

> +#define PL061_GPIO_PERIPH_ID3           0xFEC

> +

> +#define PL061_GPIO_PCELL_ID0            0xFF0

> +#define PL061_GPIO_PCELL_ID1            0xFF4

> +#define PL061_GPIO_PCELL_ID2            0xFF8

> +#define PL061_GPIO_PCELL_ID3            0xFFC

> +

> +#define PL061_GPIO_PINS                 8

>  

>  // All bits low except one bit high, native bit length

>  #define GPIO_PIN_MASK(Pin)              (1UL << ((UINTN)(Pin)))

> -- 

> 1.9.1

> 

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
Haojian Zhuang March 14, 2016, 1:38 p.m. UTC | #2
在 03/14/2016 09:19 PM, Leif Lindholm 写道:
> On Mon, Mar 14, 2016 at 01:30:37PM +0800, Haojian Zhuang wrote:
>> Support multiple PL061 controllers. If platform gpio driver couldn't be
>> found, PL061 gpio driver will continue to load PcdPL061GpioBase as the
>> register base.
>>
>> It could be compatible with the use case of current PL061 gpio driver.
>
> The content looks fine.
> There are two whitespace errors, which are picked up by
> BaseTools/Scripts/PatchCheck.py. Now, given that I've already been a
> pain over this set, I don't mind fixing it up on commit, but it's
> worth integrating this step into your workflow.
>

Thanks a lot. I'll use this script to check my patch.

Best Regards
Haojian
diff mbox

Patch

diff --git a/ArmPlatformPkg/Drivers/PL061GpioDxe/PL061Gpio.c b/ArmPlatformPkg/Drivers/PL061GpioDxe/PL061Gpio.c
index 38341a3..59d615d 100644
--- a/ArmPlatformPkg/Drivers/PL061GpioDxe/PL061Gpio.c
+++ b/ArmPlatformPkg/Drivers/PL061GpioDxe/PL061Gpio.c
@@ -20,6 +20,7 @@ 
 #include <Library/BaseMemoryLib.h>
 #include <Library/DebugLib.h>
 #include <Library/IoLib.h>
+#include <Library/MemoryAllocationLib.h>
 #include <Library/PcdLib.h>
 #include <Library/UefiBootServicesTableLib.h>
 #include <Library/UefiLib.h>
@@ -28,6 +29,33 @@ 
 #include <Protocol/EmbeddedGpio.h>
 #include <Drivers/PL061Gpio.h>
 
+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 9d9e4cd..405a3a9 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 8fde2bb..308f69f 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_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_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)
-
-
-// GPIO pins are numbered 0..7
-#define LAST_GPIO_PIN                   7
+#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           0xFE0
+#define PL061_GPIO_PERIPH_ID1           0xFE4
+#define PL061_GPIO_PERIPH_ID2           0xFE8
+#define PL061_GPIO_PERIPH_ID3           0xFEC
+
+#define PL061_GPIO_PCELL_ID0            0xFF0
+#define PL061_GPIO_PCELL_ID1            0xFF4
+#define PL061_GPIO_PCELL_ID2            0xFF8
+#define PL061_GPIO_PCELL_ID3            0xFFC
+
+#define PL061_GPIO_PINS                 8
 
 // All bits low except one bit high, native bit length
 #define GPIO_PIN_MASK(Pin)              (1UL << ((UINTN)(Pin)))