3 Copyright (c) 2011 - 2020, Arm Limited. All rights reserved.<BR>
4 Copyright (c) 2016, Linaro Limited. All rights reserved.
6 SPDX-License-Identifier: BSD-2-Clause-Patent
13 #include <Library/BaseLib.h>
14 #include <Library/BaseMemoryLib.h>
15 #include <Library/DebugLib.h>
16 #include <Library/IoLib.h>
17 #include <Library/MemoryAllocationLib.h>
18 #include <Library/PcdLib.h>
19 #include <Library/UefiBootServicesTableLib.h>
20 #include <Library/UefiLib.h>
21 #include <Library/UefiRuntimeServicesTableLib.h>
23 #include <Protocol/EmbeddedGpio.h>
25 #include "PL061Gpio.h"
27 PLATFORM_GPIO_CONTROLLER
*mPL061PlatformGpio
;
32 IN EMBEDDED_GPIO_PIN Gpio
,
33 OUT UINTN
*ControllerIndex
,
34 OUT UINTN
*ControllerOffset
,
35 OUT UINTN
*RegisterBase
40 for (Index
= 0; Index
< mPL061PlatformGpio
->GpioControllerCount
; Index
++) {
41 if ( (Gpio
>= mPL061PlatformGpio
->GpioController
[Index
].GpioIndex
)
42 && (Gpio
< mPL061PlatformGpio
->GpioController
[Index
].GpioIndex
43 + mPL061PlatformGpio
->GpioController
[Index
].InternalGpioCount
)) {
44 *ControllerIndex
= Index
;
45 *ControllerOffset
= Gpio
% mPL061PlatformGpio
->GpioController
[Index
].InternalGpioCount
;
46 *RegisterBase
= mPL061PlatformGpio
->GpioController
[Index
].RegisterBase
;
50 DEBUG ((EFI_D_ERROR
, "%a, failed to locate gpio %d\n", __func__
, Gpio
));
51 return EFI_INVALID_PARAMETER
;
55 // The PL061 is a strange beast. The 8-bit data register is aliased across a
56 // region 0x400 bytes in size, with bits [9:2] of the address operating as a
57 // mask for both read and write operations:
59 // - All bits where their corresponding mask bit is 1 return the current
60 // value of that bit in the GPIO_DATA register.
61 // - All bits where their corresponding mask bit is 0 return 0.
63 // - All bits where their corresponding mask bit is 1 set the bit in the
64 // GPIO_DATA register to the written value.
65 // - All bits where their corresponding mask bit is 0 are left untouched
66 // in the GPIO_DATA register.
68 // To keep this driver intelligible, PL061EffectiveAddress, PL061GetPins and
69 // Pl061SetPins provide an internal abstraction from this interface.
74 PL061EffectiveAddress (
79 return ((Address
+ PL061_GPIO_DATA_REG_OFFSET
) + (Mask
<< 2));
90 return MmioRead8 (PL061EffectiveAddress (Address
, Mask
));
102 MmioWrite8 (PL061EffectiveAddress (Address
, Mask
), Value
);
106 Function implementations
117 if ( (mPL061PlatformGpio
->GpioCount
== 0)
118 || (mPL061PlatformGpio
->GpioControllerCount
== 0)) {
119 return EFI_NOT_FOUND
;
122 for (Index
= 0; Index
< mPL061PlatformGpio
->GpioControllerCount
; Index
++) {
123 if (mPL061PlatformGpio
->GpioController
[Index
].InternalGpioCount
!= PL061_GPIO_PINS
) {
124 return EFI_INVALID_PARAMETER
;
127 RegisterBase
= mPL061PlatformGpio
->GpioController
[Index
].RegisterBase
;
129 // Check if this is a PrimeCell Peripheral
130 if ( (MmioRead8 (RegisterBase
+ PL061_GPIO_PCELL_ID0
) != 0x0D)
131 || (MmioRead8 (RegisterBase
+ PL061_GPIO_PCELL_ID1
) != 0xF0)
132 || (MmioRead8 (RegisterBase
+ PL061_GPIO_PCELL_ID2
) != 0x05)
133 || (MmioRead8 (RegisterBase
+ PL061_GPIO_PCELL_ID3
) != 0xB1)) {
134 return EFI_NOT_FOUND
;
137 // Check if this PrimeCell Peripheral is the PL061 GPIO
138 if ( (MmioRead8 (RegisterBase
+ PL061_GPIO_PERIPH_ID0
) != 0x61)
139 || (MmioRead8 (RegisterBase
+ PL061_GPIO_PERIPH_ID1
) != 0x10)
140 || ((MmioRead8 (RegisterBase
+ PL061_GPIO_PERIPH_ID2
) & 0xF) != 0x04)
141 || (MmioRead8 (RegisterBase
+ PL061_GPIO_PERIPH_ID3
) != 0x00)) {
142 return EFI_NOT_FOUND
;
153 Gets the state of a GPIO pin
157 This - pointer to protocol
158 Gpio - which pin to read
159 Value - state of the pin
163 EFI_SUCCESS - GPIO state returned in Value
164 EFI_INVALID_PARAMETER - Value is NULL pointer or Gpio pin is out of range
169 IN EMBEDDED_GPIO
*This
,
170 IN EMBEDDED_GPIO_PIN Gpio
,
175 UINTN Index
, Offset
, RegisterBase
;
177 Status
= PL061Locate (Gpio
, &Index
, &Offset
, &RegisterBase
);
178 ASSERT_EFI_ERROR (Status
);
181 return EFI_INVALID_PARAMETER
;
184 if (PL061GetPins (RegisterBase
, GPIO_PIN_MASK(Offset
)) != 0) {
197 Sets the state of a GPIO pin
201 This - pointer to protocol
202 Gpio - which pin to modify
207 EFI_SUCCESS - GPIO set as requested
208 EFI_UNSUPPORTED - Mode is not supported
209 EFI_INVALID_PARAMETER - Gpio pin is out of range
214 IN EMBEDDED_GPIO
*This
,
215 IN EMBEDDED_GPIO_PIN Gpio
,
216 IN EMBEDDED_GPIO_MODE Mode
220 UINTN Index
, Offset
, RegisterBase
;
222 Status
= PL061Locate (Gpio
, &Index
, &Offset
, &RegisterBase
);
223 ASSERT_EFI_ERROR (Status
);
227 case GPIO_MODE_INPUT
:
228 // Set the corresponding direction bit to LOW for input
229 MmioAnd8 (RegisterBase
+ PL061_GPIO_DIR_REG
,
230 ~GPIO_PIN_MASK(Offset
) & 0xFF);
233 case GPIO_MODE_OUTPUT_0
:
234 // Set the corresponding direction bit to HIGH for output
235 MmioOr8 (RegisterBase
+ PL061_GPIO_DIR_REG
, GPIO_PIN_MASK(Offset
));
236 // Set the corresponding data bit to LOW for 0
237 PL061SetPins (RegisterBase
, GPIO_PIN_MASK(Offset
), 0);
240 case GPIO_MODE_OUTPUT_1
:
241 // Set the corresponding direction bit to HIGH for output
242 MmioOr8 (RegisterBase
+ PL061_GPIO_DIR_REG
, GPIO_PIN_MASK(Offset
));
243 // Set the corresponding data bit to HIGH for 1
244 PL061SetPins (RegisterBase
, GPIO_PIN_MASK(Offset
), 0xff);
248 // Other modes are not supported
249 return EFI_UNSUPPORTED
;
259 Gets the mode (function) of a GPIO pin
263 This - pointer to protocol
265 Mode - pointer to output mode value
269 EFI_SUCCESS - mode value retrieved
270 EFI_INVALID_PARAMETER - Mode is a null pointer or Gpio pin is out of range
276 IN EMBEDDED_GPIO
*This
,
277 IN EMBEDDED_GPIO_PIN Gpio
,
278 OUT EMBEDDED_GPIO_MODE
*Mode
282 UINTN Index
, Offset
, RegisterBase
;
284 Status
= PL061Locate (Gpio
, &Index
, &Offset
, &RegisterBase
);
285 ASSERT_EFI_ERROR (Status
);
289 return EFI_INVALID_PARAMETER
;
292 // Check if it is input or output
293 if (MmioRead8 (RegisterBase
+ PL061_GPIO_DIR_REG
) & GPIO_PIN_MASK(Offset
)) {
295 if (PL061GetPins (RegisterBase
, GPIO_PIN_MASK(Offset
)) != 0) {
296 *Mode
= GPIO_MODE_OUTPUT_1
;
298 *Mode
= GPIO_MODE_OUTPUT_0
;
302 *Mode
= GPIO_MODE_INPUT
;
312 Sets the pull-up / pull-down resistor of a GPIO pin
316 This - pointer to protocol
318 Direction - pull-up, pull-down, or none
322 EFI_UNSUPPORTED - Can not perform the requested operation
328 IN EMBEDDED_GPIO
*This
,
329 IN EMBEDDED_GPIO_PIN Gpio
,
330 IN EMBEDDED_GPIO_PULL Direction
333 return EFI_UNSUPPORTED
;
337 Protocol variable definition
339 EMBEDDED_GPIO gGpio
= {
347 Initialize the state information for the Embedded Gpio protocol.
349 @param ImageHandle of the loaded driver
350 @param SystemTable Pointer to the System Table
352 @retval EFI_SUCCESS Protocol registered
353 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
354 @retval EFI_DEVICE_ERROR Hardware problems
359 PL061InstallProtocol (
360 IN EFI_HANDLE ImageHandle
,
361 IN EFI_SYSTEM_TABLE
*SystemTable
366 GPIO_CONTROLLER
*GpioController
;
369 // Make sure the Gpio protocol has not been installed in the system yet.
371 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL
, &gEmbeddedGpioProtocolGuid
);
373 Status
= gBS
->LocateProtocol (&gPlatformGpioProtocolGuid
, NULL
, (VOID
**)&mPL061PlatformGpio
);
374 if (EFI_ERROR (Status
) && (Status
== EFI_NOT_FOUND
)) {
375 // Create the mPL061PlatformGpio
376 mPL061PlatformGpio
= (PLATFORM_GPIO_CONTROLLER
*)AllocateZeroPool (sizeof (PLATFORM_GPIO_CONTROLLER
) + sizeof (GPIO_CONTROLLER
));
377 if (mPL061PlatformGpio
== NULL
) {
378 DEBUG ((EFI_D_ERROR
, "%a: failed to allocate PLATFORM_GPIO_CONTROLLER\n", __func__
));
379 return EFI_BAD_BUFFER_SIZE
;
382 mPL061PlatformGpio
->GpioCount
= PL061_GPIO_PINS
;
383 mPL061PlatformGpio
->GpioControllerCount
= 1;
384 mPL061PlatformGpio
->GpioController
= (GPIO_CONTROLLER
*)((UINTN
) mPL061PlatformGpio
+ sizeof (PLATFORM_GPIO_CONTROLLER
));
386 GpioController
= mPL061PlatformGpio
->GpioController
;
387 GpioController
->RegisterBase
= (UINTN
) PcdGet32 (PcdPL061GpioBase
);
388 GpioController
->GpioIndex
= 0;
389 GpioController
->InternalGpioCount
= PL061_GPIO_PINS
;
392 Status
= PL061Identify();
393 if (EFI_ERROR(Status
)) {
394 return EFI_DEVICE_ERROR
;
397 // Install the Embedded GPIO Protocol onto a new handle
399 Status
= gBS
->InstallMultipleProtocolInterfaces(
401 &gEmbeddedGpioProtocolGuid
, &gGpio
,
404 if (EFI_ERROR(Status
)) {
405 Status
= EFI_OUT_OF_RESOURCES
;