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>
This commit is contained in:
Haojian Zhuang 2016-03-14 13:30:37 +08:00 committed by Leif Lindholm
parent 78741ce91e
commit 727894d5c9
3 changed files with 126 additions and 56 deletions

View File

@ -20,6 +20,7 @@
#include <Library/BaseMemoryLib.h> #include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h> #include <Library/DebugLib.h>
#include <Library/IoLib.h> #include <Library/IoLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/PcdLib.h> #include <Library/PcdLib.h>
#include <Library/UefiBootServicesTableLib.h> #include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h> #include <Library/UefiLib.h>
@ -28,6 +29,33 @@
#include <Protocol/EmbeddedGpio.h> #include <Protocol/EmbeddedGpio.h>
#include <Drivers/PL061Gpio.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 // 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 // region 0x400 bytes in size, with bits [9:2] of the address operating as a
@ -88,20 +116,36 @@ PL061Identify (
VOID VOID
) )
{ {
// Check if this is a PrimeCell Peripheral UINTN Index;
if ( (MmioRead8 (PL061_GPIO_PCELL_ID0) != 0x0D) UINTN RegisterBase;
|| (MmioRead8 (PL061_GPIO_PCELL_ID1) != 0xF0)
|| (MmioRead8 (PL061_GPIO_PCELL_ID2) != 0x05) if ( (mPL061PlatformGpio->GpioCount == 0)
|| (MmioRead8 (PL061_GPIO_PCELL_ID3) != 0xB1)) { || (mPL061PlatformGpio->GpioControllerCount == 0)) {
return EFI_NOT_FOUND; return EFI_NOT_FOUND;
} }
// Check if this PrimeCell Peripheral is the PL061 GPIO for (Index = 0; Index < mPL061PlatformGpio->GpioControllerCount; Index++) {
if ( (MmioRead8 (PL061_GPIO_PERIPH_ID0) != 0x61) if (mPL061PlatformGpio->GpioController[Index].InternalGpioCount != PL061_GPIO_PINS) {
|| (MmioRead8 (PL061_GPIO_PERIPH_ID1) != 0x10) return EFI_INVALID_PARAMETER;
|| ((MmioRead8 (PL061_GPIO_PERIPH_ID2) & 0xF) != 0x04) }
|| (MmioRead8 (PL061_GPIO_PERIPH_ID3) != 0x00)) {
return EFI_NOT_FOUND; 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; return EFI_SUCCESS;
@ -132,13 +176,17 @@ Get (
OUT UINTN *Value OUT UINTN *Value
) )
{ {
if ( (Value == NULL) EFI_STATUS Status = EFI_SUCCESS;
|| (Gpio > LAST_GPIO_PIN)) UINTN Index, Offset, RegisterBase;
{
Status = PL061Locate (Gpio, &Index, &Offset, &RegisterBase);
ASSERT_EFI_ERROR (Status);
if (Value == NULL) {
return EFI_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
} }
if (PL061GetPins (PL061_GPIO_DATA_REG, Gpio)) { if (PL061GetPins (RegisterBase + PL061_GPIO_DATA_REG, Offset)) {
*Value = 1; *Value = 1;
} else { } else {
*Value = 0; *Value = 0;
@ -174,41 +222,39 @@ Set (
) )
{ {
EFI_STATUS Status = EFI_SUCCESS; EFI_STATUS Status = EFI_SUCCESS;
UINTN Index, Offset, RegisterBase;
// Check for errors Status = PL061Locate (Gpio, &Index, &Offset, &RegisterBase);
if (Gpio > LAST_GPIO_PIN) { ASSERT_EFI_ERROR (Status);
Status = EFI_INVALID_PARAMETER;
goto EXIT;
}
switch (Mode) switch (Mode)
{ {
case GPIO_MODE_INPUT: case GPIO_MODE_INPUT:
// Set the corresponding direction bit to LOW for 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; break;
case GPIO_MODE_OUTPUT_0: case GPIO_MODE_OUTPUT_0:
// Set the corresponding direction bit to HIGH for output // 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 // 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; break;
case GPIO_MODE_OUTPUT_1: case GPIO_MODE_OUTPUT_1:
// Set the corresponding direction bit to HIGH for output // 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 // Set the corresponding data bit to HIGH for 1
PL061SetPins (PL061_GPIO_DATA_REG, GPIO_PIN_MASK(Gpio), 0xff); PL061SetPins (RegisterBase + PL061_GPIO_DATA_REG, GPIO_PIN_MASK(Offset), 0xff);
break; break;
default: default:
// Other modes are not supported // Other modes are not supported
return EFI_UNSUPPORTED; return EFI_UNSUPPORTED;
} }
EXIT: return EFI_SUCCESS;
return Status;
} }
/** /**
@ -237,16 +283,21 @@ GetMode (
OUT EMBEDDED_GPIO_MODE *Mode 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 // Check for errors
if ( (Mode == NULL) if (Mode == NULL) {
|| (Gpio > LAST_GPIO_PIN)) {
return EFI_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
} }
// Check if it is input or output // 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 // 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; *Mode = GPIO_MODE_OUTPUT_1;
} else { } else {
*Mode = GPIO_MODE_OUTPUT_0; *Mode = GPIO_MODE_OUTPUT_0;
@ -315,14 +366,34 @@ PL061InstallProtocol (
IN EFI_SYSTEM_TABLE *SystemTable IN EFI_SYSTEM_TABLE *SystemTable
) )
{ {
EFI_STATUS Status; EFI_STATUS Status;
EFI_HANDLE Handle; EFI_HANDLE Handle;
GPIO_CONTROLLER *GpioController;
// //
// Make sure the Gpio protocol has not been installed in the system yet. // Make sure the Gpio protocol has not been installed in the system yet.
// //
ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEmbeddedGpioProtocolGuid); 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(); Status = PL061Identify();
if (EFI_ERROR(Status)) { if (EFI_ERROR(Status)) {
return EFI_DEVICE_ERROR; return EFI_DEVICE_ERROR;

View File

@ -45,6 +45,7 @@
[Protocols] [Protocols]
gEmbeddedGpioProtocolGuid gEmbeddedGpioProtocolGuid
gPlatformGpioProtocolGuid
[Depex] [Depex]
TRUE TRUE

View File

@ -20,30 +20,28 @@
// PL061 GPIO Registers // PL061 GPIO Registers
#define PL061_GPIO_DATA_REG_OFFSET ((UINTN) 0x000) #define PL061_GPIO_DATA_REG_OFFSET ((UINTN) 0x000)
#define PL061_GPIO_DATA_REG ((UINT32)PcdGet32 (PcdPL061GpioBase) + 0x000) #define PL061_GPIO_DATA_REG 0x000
#define PL061_GPIO_DIR_REG ((UINT32)PcdGet32 (PcdPL061GpioBase) + 0x400) #define PL061_GPIO_DIR_REG 0x400
#define PL061_GPIO_IS_REG ((UINT32)PcdGet32 (PcdPL061GpioBase) + 0x404) #define PL061_GPIO_IS_REG 0x404
#define PL061_GPIO_IBE_REG ((UINT32)PcdGet32 (PcdPL061GpioBase) + 0x408) #define PL061_GPIO_IBE_REG 0x408
#define PL061_GPIO_IEV_REG ((UINT32)PcdGet32 (PcdPL061GpioBase) + 0x40C) #define PL061_GPIO_IEV_REG 0x40C
#define PL061_GPIO_IE_REG ((UINT32)PcdGet32 (PcdPL061GpioBase) + 0x410) #define PL061_GPIO_IE_REG 0x410
#define PL061_GPIO_RIS_REG ((UINT32)PcdGet32 (PcdPL061GpioBase) + 0x414) #define PL061_GPIO_RIS_REG 0x414
#define PL061_GPIO_MIS_REG ((UINT32)PcdGet32 (PcdPL061GpioBase) + 0x410) #define PL061_GPIO_MIS_REG 0x410
#define PL061_GPIO_IC_REG ((UINT32)PcdGet32 (PcdPL061GpioBase) + 0x41C) #define PL061_GPIO_IC_REG 0x41C
#define PL061_GPIO_AFSEL_REG ((UINT32)PcdGet32 (PcdPL061GpioBase) + 0x420) #define PL061_GPIO_AFSEL_REG 0x420
#define PL061_GPIO_PERIPH_ID0 ((UINT32)PcdGet32 (PcdPL061GpioBase) + 0xFE0) #define PL061_GPIO_PERIPH_ID0 0xFE0
#define PL061_GPIO_PERIPH_ID1 ((UINT32)PcdGet32 (PcdPL061GpioBase) + 0xFE4) #define PL061_GPIO_PERIPH_ID1 0xFE4
#define PL061_GPIO_PERIPH_ID2 ((UINT32)PcdGet32 (PcdPL061GpioBase) + 0xFE8) #define PL061_GPIO_PERIPH_ID2 0xFE8
#define PL061_GPIO_PERIPH_ID3 ((UINT32)PcdGet32 (PcdPL061GpioBase) + 0xFEC) #define PL061_GPIO_PERIPH_ID3 0xFEC
#define PL061_GPIO_PCELL_ID0 ((UINT32)PcdGet32 (PcdPL061GpioBase) + 0xFF0) #define PL061_GPIO_PCELL_ID0 0xFF0
#define PL061_GPIO_PCELL_ID1 ((UINT32)PcdGet32 (PcdPL061GpioBase) + 0xFF4) #define PL061_GPIO_PCELL_ID1 0xFF4
#define PL061_GPIO_PCELL_ID2 ((UINT32)PcdGet32 (PcdPL061GpioBase) + 0xFF8) #define PL061_GPIO_PCELL_ID2 0xFF8
#define PL061_GPIO_PCELL_ID3 ((UINT32)PcdGet32 (PcdPL061GpioBase) + 0xFFC) #define PL061_GPIO_PCELL_ID3 0xFFC
#define PL061_GPIO_PINS 8
// GPIO pins are numbered 0..7
#define LAST_GPIO_PIN 7
// All bits low except one bit high, native bit length // All bits low except one bit high, native bit length
#define GPIO_PIN_MASK(Pin) (1UL << ((UINTN)(Pin))) #define GPIO_PIN_MASK(Pin) (1UL << ((UINTN)(Pin)))