/** @file\r
*\r
* Copyright (c) 2011, ARM Limited. All rights reserved.\r
+* Copyright (c) 2016, Linaro Limited. All rights reserved.\r
*\r
* This program and the accompanying materials\r
* are licensed and made available under the terms and conditions of the BSD\r
#include <Library/BaseMemoryLib.h>\r
#include <Library/DebugLib.h>\r
#include <Library/IoLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
#include <Library/PcdLib.h>\r
#include <Library/UefiBootServicesTableLib.h>\r
#include <Library/UefiLib.h>\r
#include <Protocol/EmbeddedGpio.h>\r
#include <Drivers/PL061Gpio.h>\r
\r
-BOOLEAN mPL061Initialized = FALSE;\r
-\r
-/**\r
- Function implementations\r
-**/\r
+PLATFORM_GPIO_CONTROLLER *mPL061PlatformGpio;\r
\r
EFI_STATUS\r
-PL061Identify (\r
- VOID\r
+EFIAPI\r
+PL061Locate (\r
+ IN EMBEDDED_GPIO_PIN Gpio,\r
+ OUT UINTN *ControllerIndex,\r
+ OUT UINTN *ControllerOffset,\r
+ OUT UINTN *RegisterBase\r
)\r
{\r
- // Check if this is a PrimeCell Peripheral\r
- if ( (MmioRead8 (PL061_GPIO_PCELL_ID0) != 0x0D)\r
- || (MmioRead8 (PL061_GPIO_PCELL_ID1) != 0xF0)\r
- || (MmioRead8 (PL061_GPIO_PCELL_ID2) != 0x05)\r
- || (MmioRead8 (PL061_GPIO_PCELL_ID3) != 0xB1)) {\r
- return EFI_NOT_FOUND;\r
+ UINT32 Index;\r
+\r
+ for (Index = 0; Index < mPL061PlatformGpio->GpioControllerCount; Index++) {\r
+ if ( (Gpio >= mPL061PlatformGpio->GpioController[Index].GpioIndex)\r
+ && (Gpio < mPL061PlatformGpio->GpioController[Index].GpioIndex\r
+ + mPL061PlatformGpio->GpioController[Index].InternalGpioCount)) {\r
+ *ControllerIndex = Index;\r
+ *ControllerOffset = Gpio % mPL061PlatformGpio->GpioController[Index].InternalGpioCount;\r
+ *RegisterBase = mPL061PlatformGpio->GpioController[Index].RegisterBase;\r
+ return EFI_SUCCESS;\r
+ }\r
}\r
+ DEBUG ((EFI_D_ERROR, "%a, failed to locate gpio %d\n", __func__, Gpio));\r
+ return EFI_INVALID_PARAMETER;\r
+}\r
\r
- // Check if this PrimeCell Peripheral is the PL061 GPIO\r
- if ( (MmioRead8 (PL061_GPIO_PERIPH_ID0) != 0x61)\r
- || (MmioRead8 (PL061_GPIO_PERIPH_ID1) != 0x10)\r
- || ((MmioRead8 (PL061_GPIO_PERIPH_ID2) & 0xF) != 0x04)\r
- || (MmioRead8 (PL061_GPIO_PERIPH_ID3) != 0x00)) {\r
- return EFI_NOT_FOUND;\r
- }\r
+//\r
+// The PL061 is a strange beast. The 8-bit data register is aliased across a\r
+// region 0x400 bytes in size, with bits [9:2] of the address operating as a\r
+// mask for both read and write operations:\r
+// For reads:\r
+// - All bits where their corresponding mask bit is 1 return the current\r
+// value of that bit in the GPIO_DATA register.\r
+// - All bits where their corresponding mask bit is 0 return 0.\r
+// For writes:\r
+// - All bits where their corresponding mask bit is 1 set the bit in the\r
+// GPIO_DATA register to the written value.\r
+// - All bits where their corresponding mask bit is 0 are left untouched\r
+// in the GPIO_DATA register.\r
+//\r
+// To keep this driver intelligible, PL061EffectiveAddress, PL061GetPins and\r
+// Pl061SetPins provide an internal abstraction from this interface.\r
+\r
+STATIC\r
+UINTN\r
+EFIAPI\r
+PL061EffectiveAddress (\r
+ IN UINTN Address,\r
+ IN UINTN Mask\r
+ )\r
+{\r
+ return ((Address + PL061_GPIO_DATA_REG_OFFSET) + (Mask << 2));\r
+}\r
\r
- return EFI_SUCCESS;\r
+STATIC\r
+UINTN\r
+EFIAPI\r
+PL061GetPins (\r
+ IN UINTN Address,\r
+ IN UINTN Mask\r
+ )\r
+{\r
+ return MmioRead8 (PL061EffectiveAddress (Address, Mask));\r
}\r
\r
+STATIC\r
+VOID\r
+EFIAPI\r
+PL061SetPins (\r
+ IN UINTN Address,\r
+ IN UINTN Mask,\r
+ IN UINTN Value\r
+ )\r
+{\r
+ MmioWrite8 (PL061EffectiveAddress (Address, Mask), Value);\r
+}\r
+\r
+/**\r
+ Function implementations\r
+**/\r
+\r
EFI_STATUS\r
-PL061Initialize (\r
+PL061Identify (\r
VOID\r
)\r
{\r
- EFI_STATUS Status;\r
+ UINTN Index;\r
+ UINTN RegisterBase;\r
\r
- // Check if the PL061 GPIO module exists on board\r
- Status = PL061Identify();\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_DEVICE_ERROR;\r
- goto EXIT;\r
+ if ( (mPL061PlatformGpio->GpioCount == 0)\r
+ || (mPL061PlatformGpio->GpioControllerCount == 0)) {\r
+ return EFI_NOT_FOUND;\r
}\r
\r
- // Do other hardware initialisation things here as required\r
+ for (Index = 0; Index < mPL061PlatformGpio->GpioControllerCount; Index++) {\r
+ if (mPL061PlatformGpio->GpioController[Index].InternalGpioCount != PL061_GPIO_PINS) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
\r
- // Disable Interrupts\r
- //if (MmioRead8 (PL061_GPIO_IE_REG) != 0) {\r
- // // Ensure interrupts are disabled\r
- //}\r
+ RegisterBase = mPL061PlatformGpio->GpioController[Index].RegisterBase;\r
\r
- mPL061Initialized = TRUE;\r
+ // Check if this is a PrimeCell Peripheral\r
+ if ( (MmioRead8 (RegisterBase + PL061_GPIO_PCELL_ID0) != 0x0D)\r
+ || (MmioRead8 (RegisterBase + PL061_GPIO_PCELL_ID1) != 0xF0)\r
+ || (MmioRead8 (RegisterBase + PL061_GPIO_PCELL_ID2) != 0x05)\r
+ || (MmioRead8 (RegisterBase + PL061_GPIO_PCELL_ID3) != 0xB1)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
\r
- EXIT:\r
- return Status;\r
+ // Check if this PrimeCell Peripheral is the PL061 GPIO\r
+ if ( (MmioRead8 (RegisterBase + PL061_GPIO_PERIPH_ID0) != 0x61)\r
+ || (MmioRead8 (RegisterBase + PL061_GPIO_PERIPH_ID1) != 0x10)\r
+ || ((MmioRead8 (RegisterBase + PL061_GPIO_PERIPH_ID2) & 0xF) != 0x04)\r
+ || (MmioRead8 (RegisterBase + PL061_GPIO_PERIPH_ID3) != 0x00)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
}\r
\r
/**\r
)\r
{\r
EFI_STATUS Status = EFI_SUCCESS;\r
+ UINTN Index, Offset, RegisterBase;\r
\r
- if ( (Value == NULL)\r
- || (Gpio > LAST_GPIO_PIN))\r
- {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
+ Status = PL061Locate (Gpio, &Index, &Offset, &RegisterBase);\r
+ ASSERT_EFI_ERROR (Status);\r
\r
- // Initialize the hardware if not already done\r
- if (!mPL061Initialized) {\r
- Status = PL061Initialize();\r
- if (EFI_ERROR(Status)) {\r
- goto EXIT;\r
- }\r
+ if (Value == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
}\r
\r
- if (MmioRead8 (PL061_GPIO_DATA_REG) & GPIO_PIN_MASK_HIGH_8BIT(Gpio)) {\r
+ if (PL061GetPins (RegisterBase, GPIO_PIN_MASK(Offset))) {\r
*Value = 1;\r
} else {\r
*Value = 0;\r
}\r
\r
- EXIT:\r
- return Status;\r
+ return EFI_SUCCESS;\r
}\r
\r
/**\r
)\r
{\r
EFI_STATUS Status = EFI_SUCCESS;\r
+ UINTN Index, Offset, RegisterBase;\r
\r
- // Check for errors\r
- if (Gpio > LAST_GPIO_PIN) {\r
- Status = EFI_INVALID_PARAMETER;\r
- goto EXIT;\r
- }\r
-\r
- // Initialize the hardware if not already done\r
- if (!mPL061Initialized) {\r
- Status = PL061Initialize();\r
- if (EFI_ERROR(Status)) {\r
- goto EXIT;\r
- }\r
- }\r
+ Status = PL061Locate (Gpio, &Index, &Offset, &RegisterBase);\r
+ ASSERT_EFI_ERROR (Status);\r
\r
switch (Mode)\r
{\r
case GPIO_MODE_INPUT:\r
// Set the corresponding direction bit to LOW for input\r
- MmioAnd8 (PL061_GPIO_DIR_REG, GPIO_PIN_MASK_LOW_8BIT(Gpio));\r
+ MmioAnd8 (RegisterBase + PL061_GPIO_DIR_REG,\r
+ ~GPIO_PIN_MASK(Offset) & 0xFF);\r
break;\r
\r
case GPIO_MODE_OUTPUT_0:\r
- // Set the corresponding data bit to LOW for 0\r
- MmioAnd8 (PL061_GPIO_DATA_REG, GPIO_PIN_MASK_LOW_8BIT(Gpio));\r
// Set the corresponding direction bit to HIGH for output\r
- MmioOr8 (PL061_GPIO_DIR_REG, GPIO_PIN_MASK_HIGH_8BIT(Gpio));\r
+ MmioOr8 (RegisterBase + PL061_GPIO_DIR_REG, GPIO_PIN_MASK(Offset));\r
+ // Set the corresponding data bit to LOW for 0\r
+ PL061SetPins (RegisterBase, GPIO_PIN_MASK(Offset), 0);\r
break;\r
\r
case GPIO_MODE_OUTPUT_1:\r
- // Set the corresponding data bit to HIGH for 1\r
- MmioOr8 (PL061_GPIO_DATA_REG, GPIO_PIN_MASK_HIGH_8BIT(Gpio));\r
// Set the corresponding direction bit to HIGH for output\r
- MmioOr8 (PL061_GPIO_DIR_REG, GPIO_PIN_MASK_HIGH_8BIT(Gpio));\r
+ MmioOr8 (RegisterBase + PL061_GPIO_DIR_REG, GPIO_PIN_MASK(Offset));\r
+ // Set the corresponding data bit to HIGH for 1\r
+ PL061SetPins (RegisterBase, GPIO_PIN_MASK(Offset), 0xff);\r
break;\r
\r
default:\r
return EFI_UNSUPPORTED;\r
}\r
\r
-EXIT:\r
- return Status;\r
+ return EFI_SUCCESS;\r
}\r
\r
/**\r
OUT EMBEDDED_GPIO_MODE *Mode\r
)\r
{\r
- EFI_STATUS Status;\r
+ EFI_STATUS Status = EFI_SUCCESS;\r
+ UINTN Index, Offset, RegisterBase;\r
+\r
+ Status = PL061Locate (Gpio, &Index, &Offset, &RegisterBase);\r
+ ASSERT_EFI_ERROR (Status);\r
\r
// Check for errors\r
- if ( (Mode == NULL)\r
- || (Gpio > LAST_GPIO_PIN)) {\r
+ if (Mode == NULL) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- // Initialize the hardware if not already done\r
- if (!mPL061Initialized) {\r
- Status = PL061Initialize();\r
- if (EFI_ERROR(Status)) {\r
- return Status;\r
- }\r
- }\r
-\r
// Check if it is input or output\r
- if (MmioRead8 (PL061_GPIO_DIR_REG) & GPIO_PIN_MASK_HIGH_8BIT(Gpio)) {\r
+ if (MmioRead8 (RegisterBase + PL061_GPIO_DIR_REG) & GPIO_PIN_MASK(Offset)) {\r
// Pin set to output\r
- if (MmioRead8 (PL061_GPIO_DATA_REG) & GPIO_PIN_MASK_HIGH_8BIT(Gpio)) {\r
+ if (PL061GetPins (RegisterBase, GPIO_PIN_MASK(Offset))) {\r
*Mode = GPIO_MODE_OUTPUT_1;\r
} else {\r
*Mode = GPIO_MODE_OUTPUT_0;\r
IN EFI_SYSTEM_TABLE *SystemTable\r
)\r
{\r
- EFI_STATUS Status;\r
- EFI_HANDLE Handle;\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE Handle;\r
+ GPIO_CONTROLLER *GpioController;\r
\r
//\r
// Make sure the Gpio protocol has not been installed in the system yet.\r
//\r
ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEmbeddedGpioProtocolGuid);\r
\r
+ Status = gBS->LocateProtocol (&gPlatformGpioProtocolGuid, NULL, (VOID **)&mPL061PlatformGpio);\r
+ if (EFI_ERROR (Status) && (Status == EFI_NOT_FOUND)) {\r
+ // Create the mPL061PlatformGpio\r
+ mPL061PlatformGpio = (PLATFORM_GPIO_CONTROLLER *)AllocateZeroPool (sizeof (PLATFORM_GPIO_CONTROLLER) + sizeof (GPIO_CONTROLLER));\r
+ if (mPL061PlatformGpio == NULL) {\r
+ DEBUG ((EFI_D_ERROR, "%a: failed to allocate PLATFORM_GPIO_CONTROLLER\n", __func__));\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+\r
+ mPL061PlatformGpio->GpioCount = PL061_GPIO_PINS;\r
+ mPL061PlatformGpio->GpioControllerCount = 1;\r
+ mPL061PlatformGpio->GpioController = (GPIO_CONTROLLER *)((UINTN) mPL061PlatformGpio + sizeof (PLATFORM_GPIO_CONTROLLER));\r
+\r
+ GpioController = mPL061PlatformGpio->GpioController;\r
+ GpioController->RegisterBase = (UINTN) PcdGet32 (PcdPL061GpioBase);\r
+ GpioController->GpioIndex = 0;\r
+ GpioController->InternalGpioCount = PL061_GPIO_PINS;\r
+ }\r
+\r
+ Status = PL061Identify();\r
+ if (EFI_ERROR(Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
// Install the Embedded GPIO Protocol onto a new handle\r
Handle = NULL;\r
Status = gBS->InstallMultipleProtocolInterfaces(\r