3 * Copyright (c) 2011, ARM Limited. All rights reserved.
4 * Copyright (c) 2016, Linaro Limited. All rights reserved.
6 * This program and the accompanying materials
7 * are licensed and made available under the terms and conditions of the BSD
8 * License which accompanies this distribution. The full text of the license
9 * may be found at http://opensource.org/licenses/bsd-license.php
11 * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 #include <Library/BaseLib.h>
20 #include <Library/BaseMemoryLib.h>
21 #include <Library/DebugLib.h>
22 #include <Library/IoLib.h>
23 #include <Library/MemoryAllocationLib.h>
24 #include <Library/PcdLib.h>
25 #include <Library/UefiBootServicesTableLib.h>
26 #include <Library/UefiLib.h>
27 #include <Library/UefiRuntimeServicesTableLib.h>
29 #include <Protocol/EmbeddedGpio.h>
31 #include "PL061Gpio.h"
33 PLATFORM_GPIO_CONTROLLER
*mPL061PlatformGpio
;
38 IN EMBEDDED_GPIO_PIN Gpio
,
39 OUT UINTN
*ControllerIndex
,
40 OUT UINTN
*ControllerOffset
,
41 OUT UINTN
*RegisterBase
46 for (Index
= 0; Index
< mPL061PlatformGpio
->GpioControllerCount
; Index
++) {
47 if ( (Gpio
>= mPL061PlatformGpio
->GpioController
[Index
].GpioIndex
)
48 && (Gpio
< mPL061PlatformGpio
->GpioController
[Index
].GpioIndex
49 + mPL061PlatformGpio
->GpioController
[Index
].InternalGpioCount
)) {
50 *ControllerIndex
= Index
;
51 *ControllerOffset
= Gpio
% mPL061PlatformGpio
->GpioController
[Index
].InternalGpioCount
;
52 *RegisterBase
= mPL061PlatformGpio
->GpioController
[Index
].RegisterBase
;
56 DEBUG ((EFI_D_ERROR
, "%a, failed to locate gpio %d\n", __func__
, Gpio
));
57 return EFI_INVALID_PARAMETER
;
61 // The PL061 is a strange beast. The 8-bit data register is aliased across a
62 // region 0x400 bytes in size, with bits [9:2] of the address operating as a
63 // mask for both read and write operations:
65 // - All bits where their corresponding mask bit is 1 return the current
66 // value of that bit in the GPIO_DATA register.
67 // - All bits where their corresponding mask bit is 0 return 0.
69 // - All bits where their corresponding mask bit is 1 set the bit in the
70 // GPIO_DATA register to the written value.
71 // - All bits where their corresponding mask bit is 0 are left untouched
72 // in the GPIO_DATA register.
74 // To keep this driver intelligible, PL061EffectiveAddress, PL061GetPins and
75 // Pl061SetPins provide an internal abstraction from this interface.
80 PL061EffectiveAddress (
85 return ((Address
+ PL061_GPIO_DATA_REG_OFFSET
) + (Mask
<< 2));
96 return MmioRead8 (PL061EffectiveAddress (Address
, Mask
));
108 MmioWrite8 (PL061EffectiveAddress (Address
, Mask
), Value
);
112 Function implementations
123 if ( (mPL061PlatformGpio
->GpioCount
== 0)
124 || (mPL061PlatformGpio
->GpioControllerCount
== 0)) {
125 return EFI_NOT_FOUND
;
128 for (Index
= 0; Index
< mPL061PlatformGpio
->GpioControllerCount
; Index
++) {
129 if (mPL061PlatformGpio
->GpioController
[Index
].InternalGpioCount
!= PL061_GPIO_PINS
) {
130 return EFI_INVALID_PARAMETER
;
133 RegisterBase
= mPL061PlatformGpio
->GpioController
[Index
].RegisterBase
;
135 // Check if this is a PrimeCell Peripheral
136 if ( (MmioRead8 (RegisterBase
+ PL061_GPIO_PCELL_ID0
) != 0x0D)
137 || (MmioRead8 (RegisterBase
+ PL061_GPIO_PCELL_ID1
) != 0xF0)
138 || (MmioRead8 (RegisterBase
+ PL061_GPIO_PCELL_ID2
) != 0x05)
139 || (MmioRead8 (RegisterBase
+ PL061_GPIO_PCELL_ID3
) != 0xB1)) {
140 return EFI_NOT_FOUND
;
143 // Check if this PrimeCell Peripheral is the PL061 GPIO
144 if ( (MmioRead8 (RegisterBase
+ PL061_GPIO_PERIPH_ID0
) != 0x61)
145 || (MmioRead8 (RegisterBase
+ PL061_GPIO_PERIPH_ID1
) != 0x10)
146 || ((MmioRead8 (RegisterBase
+ PL061_GPIO_PERIPH_ID2
) & 0xF) != 0x04)
147 || (MmioRead8 (RegisterBase
+ PL061_GPIO_PERIPH_ID3
) != 0x00)) {
148 return EFI_NOT_FOUND
;
159 Gets the state of a GPIO pin
163 This - pointer to protocol
164 Gpio - which pin to read
165 Value - state of the pin
169 EFI_SUCCESS - GPIO state returned in Value
170 EFI_INVALID_PARAMETER - Value is NULL pointer or Gpio pin is out of range
175 IN EMBEDDED_GPIO
*This
,
176 IN EMBEDDED_GPIO_PIN Gpio
,
180 EFI_STATUS Status
= EFI_SUCCESS
;
181 UINTN Index
, Offset
, RegisterBase
;
183 Status
= PL061Locate (Gpio
, &Index
, &Offset
, &RegisterBase
);
184 ASSERT_EFI_ERROR (Status
);
187 return EFI_INVALID_PARAMETER
;
190 if (PL061GetPins (RegisterBase
, GPIO_PIN_MASK(Offset
))) {
203 Sets the state of a GPIO pin
207 This - pointer to protocol
208 Gpio - which pin to modify
213 EFI_SUCCESS - GPIO set as requested
214 EFI_UNSUPPORTED - Mode is not supported
215 EFI_INVALID_PARAMETER - Gpio pin is out of range
220 IN EMBEDDED_GPIO
*This
,
221 IN EMBEDDED_GPIO_PIN Gpio
,
222 IN EMBEDDED_GPIO_MODE Mode
225 EFI_STATUS Status
= EFI_SUCCESS
;
226 UINTN Index
, Offset
, RegisterBase
;
228 Status
= PL061Locate (Gpio
, &Index
, &Offset
, &RegisterBase
);
229 ASSERT_EFI_ERROR (Status
);
233 case GPIO_MODE_INPUT
:
234 // Set the corresponding direction bit to LOW for input
235 MmioAnd8 (RegisterBase
+ PL061_GPIO_DIR_REG
,
236 ~GPIO_PIN_MASK(Offset
) & 0xFF);
239 case GPIO_MODE_OUTPUT_0
:
240 // Set the corresponding direction bit to HIGH for output
241 MmioOr8 (RegisterBase
+ PL061_GPIO_DIR_REG
, GPIO_PIN_MASK(Offset
));
242 // Set the corresponding data bit to LOW for 0
243 PL061SetPins (RegisterBase
, GPIO_PIN_MASK(Offset
), 0);
246 case GPIO_MODE_OUTPUT_1
:
247 // Set the corresponding direction bit to HIGH for output
248 MmioOr8 (RegisterBase
+ PL061_GPIO_DIR_REG
, GPIO_PIN_MASK(Offset
));
249 // Set the corresponding data bit to HIGH for 1
250 PL061SetPins (RegisterBase
, GPIO_PIN_MASK(Offset
), 0xff);
254 // Other modes are not supported
255 return EFI_UNSUPPORTED
;
265 Gets the mode (function) of a GPIO pin
269 This - pointer to protocol
271 Mode - pointer to output mode value
275 EFI_SUCCESS - mode value retrieved
276 EFI_INVALID_PARAMETER - Mode is a null pointer or Gpio pin is out of range
282 IN EMBEDDED_GPIO
*This
,
283 IN EMBEDDED_GPIO_PIN Gpio
,
284 OUT EMBEDDED_GPIO_MODE
*Mode
287 EFI_STATUS Status
= EFI_SUCCESS
;
288 UINTN Index
, Offset
, RegisterBase
;
290 Status
= PL061Locate (Gpio
, &Index
, &Offset
, &RegisterBase
);
291 ASSERT_EFI_ERROR (Status
);
295 return EFI_INVALID_PARAMETER
;
298 // Check if it is input or output
299 if (MmioRead8 (RegisterBase
+ PL061_GPIO_DIR_REG
) & GPIO_PIN_MASK(Offset
)) {
301 if (PL061GetPins (RegisterBase
, GPIO_PIN_MASK(Offset
))) {
302 *Mode
= GPIO_MODE_OUTPUT_1
;
304 *Mode
= GPIO_MODE_OUTPUT_0
;
308 *Mode
= GPIO_MODE_INPUT
;
318 Sets the pull-up / pull-down resistor of a GPIO pin
322 This - pointer to protocol
324 Direction - pull-up, pull-down, or none
328 EFI_UNSUPPORTED - Can not perform the requested operation
334 IN EMBEDDED_GPIO
*This
,
335 IN EMBEDDED_GPIO_PIN Gpio
,
336 IN EMBEDDED_GPIO_PULL Direction
339 return EFI_UNSUPPORTED
;
343 Protocol variable definition
345 EMBEDDED_GPIO gGpio
= {
353 Initialize the state information for the Embedded Gpio protocol.
355 @param ImageHandle of the loaded driver
356 @param SystemTable Pointer to the System Table
358 @retval EFI_SUCCESS Protocol registered
359 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
360 @retval EFI_DEVICE_ERROR Hardware problems
365 PL061InstallProtocol (
366 IN EFI_HANDLE ImageHandle
,
367 IN EFI_SYSTEM_TABLE
*SystemTable
372 GPIO_CONTROLLER
*GpioController
;
375 // Make sure the Gpio protocol has not been installed in the system yet.
377 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL
, &gEmbeddedGpioProtocolGuid
);
379 Status
= gBS
->LocateProtocol (&gPlatformGpioProtocolGuid
, NULL
, (VOID
**)&mPL061PlatformGpio
);
380 if (EFI_ERROR (Status
) && (Status
== EFI_NOT_FOUND
)) {
381 // Create the mPL061PlatformGpio
382 mPL061PlatformGpio
= (PLATFORM_GPIO_CONTROLLER
*)AllocateZeroPool (sizeof (PLATFORM_GPIO_CONTROLLER
) + sizeof (GPIO_CONTROLLER
));
383 if (mPL061PlatformGpio
== NULL
) {
384 DEBUG ((EFI_D_ERROR
, "%a: failed to allocate PLATFORM_GPIO_CONTROLLER\n", __func__
));
385 return EFI_BAD_BUFFER_SIZE
;
388 mPL061PlatformGpio
->GpioCount
= PL061_GPIO_PINS
;
389 mPL061PlatformGpio
->GpioControllerCount
= 1;
390 mPL061PlatformGpio
->GpioController
= (GPIO_CONTROLLER
*)((UINTN
) mPL061PlatformGpio
+ sizeof (PLATFORM_GPIO_CONTROLLER
));
392 GpioController
= mPL061PlatformGpio
->GpioController
;
393 GpioController
->RegisterBase
= (UINTN
) PcdGet32 (PcdPL061GpioBase
);
394 GpioController
->GpioIndex
= 0;
395 GpioController
->InternalGpioCount
= PL061_GPIO_PINS
;
398 Status
= PL061Identify();
399 if (EFI_ERROR(Status
)) {
400 return EFI_DEVICE_ERROR
;
403 // Install the Embedded GPIO Protocol onto a new handle
405 Status
= gBS
->InstallMultipleProtocolInterfaces(
407 &gEmbeddedGpioProtocolGuid
, &gGpio
,
410 if (EFI_ERROR(Status
)) {
411 Status
= EFI_OUT_OF_RESOURCES
;