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>
30 #include <Drivers/PL061Gpio.h>
32 PLATFORM_GPIO_CONTROLLER
*mPL061PlatformGpio
;
37 IN EMBEDDED_GPIO_PIN Gpio
,
38 OUT UINTN
*ControllerIndex
,
39 OUT UINTN
*ControllerOffset
,
40 OUT UINTN
*RegisterBase
45 for (Index
= 0; Index
< mPL061PlatformGpio
->GpioControllerCount
; Index
++) {
46 if ( (Gpio
>= mPL061PlatformGpio
->GpioController
[Index
].GpioIndex
)
47 && (Gpio
< mPL061PlatformGpio
->GpioController
[Index
].GpioIndex
48 + mPL061PlatformGpio
->GpioController
[Index
].InternalGpioCount
)) {
49 *ControllerIndex
= Index
;
50 *ControllerOffset
= Gpio
% mPL061PlatformGpio
->GpioController
[Index
].InternalGpioCount
;
51 *RegisterBase
= mPL061PlatformGpio
->GpioController
[Index
].RegisterBase
;
55 DEBUG ((EFI_D_ERROR
, "%a, failed to locate gpio %d\n", __func__
, Gpio
));
56 return EFI_INVALID_PARAMETER
;
60 // The PL061 is a strange beast. The 8-bit data register is aliased across a
61 // region 0x400 bytes in size, with bits [9:2] of the address operating as a
62 // mask for both read and write operations:
64 // - All bits where their corresponding mask bit is 1 return the current
65 // value of that bit in the GPIO_DATA register.
66 // - All bits where their corresponding mask bit is 0 return 0.
68 // - All bits where their corresponding mask bit is 1 set the bit in the
69 // GPIO_DATA register to the written value.
70 // - All bits where their corresponding mask bit is 0 are left untouched
71 // in the GPIO_DATA register.
73 // To keep this driver intelligible, PL061EffectiveAddress, PL061GetPins and
74 // Pl061SetPins provide an internal abstraction from this interface.
79 PL061EffectiveAddress (
84 return ((Address
+ PL061_GPIO_DATA_REG_OFFSET
) + (Mask
<< 2));
95 return MmioRead8 (PL061EffectiveAddress (Address
, Mask
));
107 MmioWrite8 (PL061EffectiveAddress (Address
, Mask
), Value
);
111 Function implementations
122 if ( (mPL061PlatformGpio
->GpioCount
== 0)
123 || (mPL061PlatformGpio
->GpioControllerCount
== 0)) {
124 return EFI_NOT_FOUND
;
127 for (Index
= 0; Index
< mPL061PlatformGpio
->GpioControllerCount
; Index
++) {
128 if (mPL061PlatformGpio
->GpioController
[Index
].InternalGpioCount
!= PL061_GPIO_PINS
) {
129 return EFI_INVALID_PARAMETER
;
132 RegisterBase
= mPL061PlatformGpio
->GpioController
[Index
].RegisterBase
;
134 // Check if this is a PrimeCell Peripheral
135 if ( (MmioRead8 (RegisterBase
+ PL061_GPIO_PCELL_ID0
) != 0x0D)
136 || (MmioRead8 (RegisterBase
+ PL061_GPIO_PCELL_ID1
) != 0xF0)
137 || (MmioRead8 (RegisterBase
+ PL061_GPIO_PCELL_ID2
) != 0x05)
138 || (MmioRead8 (RegisterBase
+ PL061_GPIO_PCELL_ID3
) != 0xB1)) {
139 return EFI_NOT_FOUND
;
142 // Check if this PrimeCell Peripheral is the PL061 GPIO
143 if ( (MmioRead8 (RegisterBase
+ PL061_GPIO_PERIPH_ID0
) != 0x61)
144 || (MmioRead8 (RegisterBase
+ PL061_GPIO_PERIPH_ID1
) != 0x10)
145 || ((MmioRead8 (RegisterBase
+ PL061_GPIO_PERIPH_ID2
) & 0xF) != 0x04)
146 || (MmioRead8 (RegisterBase
+ PL061_GPIO_PERIPH_ID3
) != 0x00)) {
147 return EFI_NOT_FOUND
;
158 Gets the state of a GPIO pin
162 This - pointer to protocol
163 Gpio - which pin to read
164 Value - state of the pin
168 EFI_SUCCESS - GPIO state returned in Value
169 EFI_INVALID_PARAMETER - Value is NULL pointer or Gpio pin is out of range
174 IN EMBEDDED_GPIO
*This
,
175 IN EMBEDDED_GPIO_PIN Gpio
,
179 EFI_STATUS Status
= EFI_SUCCESS
;
180 UINTN Index
, Offset
, RegisterBase
;
182 Status
= PL061Locate (Gpio
, &Index
, &Offset
, &RegisterBase
);
183 ASSERT_EFI_ERROR (Status
);
186 return EFI_INVALID_PARAMETER
;
189 if (PL061GetPins (RegisterBase
, Offset
)) {
202 Sets the state of a GPIO pin
206 This - pointer to protocol
207 Gpio - which pin to modify
212 EFI_SUCCESS - GPIO set as requested
213 EFI_UNSUPPORTED - Mode is not supported
214 EFI_INVALID_PARAMETER - Gpio pin is out of range
219 IN EMBEDDED_GPIO
*This
,
220 IN EMBEDDED_GPIO_PIN Gpio
,
221 IN EMBEDDED_GPIO_MODE Mode
224 EFI_STATUS Status
= EFI_SUCCESS
;
225 UINTN Index
, Offset
, RegisterBase
;
227 Status
= PL061Locate (Gpio
, &Index
, &Offset
, &RegisterBase
);
228 ASSERT_EFI_ERROR (Status
);
232 case GPIO_MODE_INPUT
:
233 // Set the corresponding direction bit to LOW for input
234 MmioAnd8 (RegisterBase
+ PL061_GPIO_DIR_REG
,
235 ~GPIO_PIN_MASK(Offset
) & 0xFF);
238 case GPIO_MODE_OUTPUT_0
:
239 // Set the corresponding direction bit to HIGH for output
240 MmioOr8 (RegisterBase
+ PL061_GPIO_DIR_REG
, GPIO_PIN_MASK(Offset
));
241 // Set the corresponding data bit to LOW for 0
242 PL061SetPins (RegisterBase
, GPIO_PIN_MASK(Offset
), 0);
245 case GPIO_MODE_OUTPUT_1
:
246 // Set the corresponding direction bit to HIGH for output
247 MmioOr8 (RegisterBase
+ PL061_GPIO_DIR_REG
, GPIO_PIN_MASK(Offset
));
248 // Set the corresponding data bit to HIGH for 1
249 PL061SetPins (RegisterBase
, GPIO_PIN_MASK(Offset
), 0xff);
253 // Other modes are not supported
254 return EFI_UNSUPPORTED
;
264 Gets the mode (function) of a GPIO pin
268 This - pointer to protocol
270 Mode - pointer to output mode value
274 EFI_SUCCESS - mode value retrieved
275 EFI_INVALID_PARAMETER - Mode is a null pointer or Gpio pin is out of range
281 IN EMBEDDED_GPIO
*This
,
282 IN EMBEDDED_GPIO_PIN Gpio
,
283 OUT EMBEDDED_GPIO_MODE
*Mode
286 EFI_STATUS Status
= EFI_SUCCESS
;
287 UINTN Index
, Offset
, RegisterBase
;
289 Status
= PL061Locate (Gpio
, &Index
, &Offset
, &RegisterBase
);
290 ASSERT_EFI_ERROR (Status
);
294 return EFI_INVALID_PARAMETER
;
297 // Check if it is input or output
298 if (MmioRead8 (RegisterBase
+ PL061_GPIO_DIR_REG
) & GPIO_PIN_MASK(Offset
)) {
300 if (PL061GetPins (RegisterBase
, GPIO_PIN_MASK(Offset
))) {
301 *Mode
= GPIO_MODE_OUTPUT_1
;
303 *Mode
= GPIO_MODE_OUTPUT_0
;
307 *Mode
= GPIO_MODE_INPUT
;
317 Sets the pull-up / pull-down resistor of a GPIO pin
321 This - pointer to protocol
323 Direction - pull-up, pull-down, or none
327 EFI_UNSUPPORTED - Can not perform the requested operation
333 IN EMBEDDED_GPIO
*This
,
334 IN EMBEDDED_GPIO_PIN Gpio
,
335 IN EMBEDDED_GPIO_PULL Direction
338 return EFI_UNSUPPORTED
;
342 Protocol variable definition
344 EMBEDDED_GPIO gGpio
= {
352 Initialize the state information for the Embedded Gpio protocol.
354 @param ImageHandle of the loaded driver
355 @param SystemTable Pointer to the System Table
357 @retval EFI_SUCCESS Protocol registered
358 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
359 @retval EFI_DEVICE_ERROR Hardware problems
364 PL061InstallProtocol (
365 IN EFI_HANDLE ImageHandle
,
366 IN EFI_SYSTEM_TABLE
*SystemTable
371 GPIO_CONTROLLER
*GpioController
;
374 // Make sure the Gpio protocol has not been installed in the system yet.
376 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL
, &gEmbeddedGpioProtocolGuid
);
378 Status
= gBS
->LocateProtocol (&gPlatformGpioProtocolGuid
, NULL
, (VOID
**)&mPL061PlatformGpio
);
379 if (EFI_ERROR (Status
) && (Status
== EFI_NOT_FOUND
)) {
380 // Create the mPL061PlatformGpio
381 mPL061PlatformGpio
= (PLATFORM_GPIO_CONTROLLER
*)AllocateZeroPool (sizeof (PLATFORM_GPIO_CONTROLLER
) + sizeof (GPIO_CONTROLLER
));
382 if (mPL061PlatformGpio
== NULL
) {
383 DEBUG ((EFI_D_ERROR
, "%a: failed to allocate PLATFORM_GPIO_CONTROLLER\n", __func__
));
384 return EFI_BAD_BUFFER_SIZE
;
387 mPL061PlatformGpio
->GpioCount
= PL061_GPIO_PINS
;
388 mPL061PlatformGpio
->GpioControllerCount
= 1;
389 mPL061PlatformGpio
->GpioController
= (GPIO_CONTROLLER
*)((UINTN
) mPL061PlatformGpio
+ sizeof (PLATFORM_GPIO_CONTROLLER
));
391 GpioController
= mPL061PlatformGpio
->GpioController
;
392 GpioController
->RegisterBase
= (UINTN
) PcdGet32 (PcdPL061GpioBase
);
393 GpioController
->GpioIndex
= 0;
394 GpioController
->InternalGpioCount
= PL061_GPIO_PINS
;
397 Status
= PL061Identify();
398 if (EFI_ERROR(Status
)) {
399 return EFI_DEVICE_ERROR
;
402 // Install the Embedded GPIO Protocol onto a new handle
404 Status
= gBS
->InstallMultipleProtocolInterfaces(
406 &gEmbeddedGpioProtocolGuid
, &gGpio
,
409 if (EFI_ERROR(Status
)) {
410 Status
= EFI_OUT_OF_RESOURCES
;