diff options
author | Haojian Zhuang <haojian.zhuang@linaro.org> | 2016-03-14 13:30:37 +0800 |
---|---|---|
committer | Leif Lindholm <leif.lindholm@linaro.org> | 2016-03-14 13:17:34 +0000 |
commit | 727894d5c90f0fc675848d7cc56513589e63a4b7 (patch) | |
tree | 74527c20093ea085e1c40d43e8e9be1138f1145e /ArmPlatformPkg/Drivers/PL061GpioDxe/PL061Gpio.c | |
parent | 78741ce91e1285c9fbb3ba554f5f968dfca58ede (diff) | |
download | edk2-727894d5c90f0fc675848d7cc56513589e63a4b7.zip edk2-727894d5c90f0fc675848d7cc56513589e63a4b7.tar.gz edk2-727894d5c90f0fc675848d7cc56513589e63a4b7.tar.bz2 |
ArmPlatformPkg: PL061: support multiple controller
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>
Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>
Diffstat (limited to 'ArmPlatformPkg/Drivers/PL061GpioDxe/PL061Gpio.c')
-rw-r--r-- | ArmPlatformPkg/Drivers/PL061GpioDxe/PL061Gpio.c | 141 |
1 files changed, 106 insertions, 35 deletions
diff --git a/ArmPlatformPkg/Drivers/PL061GpioDxe/PL061Gpio.c b/ArmPlatformPkg/Drivers/PL061GpioDxe/PL061Gpio.c index 38341a3..0e2ea61 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;
|