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/PcdLib.h>
24 #include <Library/UefiBootServicesTableLib.h>
25 #include <Library/UefiLib.h>
26 #include <Library/UefiRuntimeServicesTableLib.h>
28 #include <Protocol/EmbeddedGpio.h>
29 #include <Drivers/PL061Gpio.h>
32 // The PL061 is a strange beast. The 8-bit data register is aliased across a
33 // region 0x400 bytes in size, with bits [9:2] of the address operating as a
34 // mask for both read and write operations:
36 // - All bits where their corresponding mask bit is 1 return the current
37 // value of that bit in the GPIO_DATA register.
38 // - All bits where their corresponding mask bit is 0 return 0.
40 // - All bits where their corresponding mask bit is 1 set the bit in the
41 // GPIO_DATA register to the written value.
42 // - All bits where their corresponding mask bit is 0 are left untouched
43 // in the GPIO_DATA register.
45 // To keep this driver intelligible, PL061EffectiveAddress, PL061GetPins and
46 // Pl061SetPins provide an internal abstraction from this interface.
51 PL061EffectiveAddress (
56 return ((Address
+ PL061_GPIO_DATA_REG_OFFSET
) + (Mask
<< 2));
67 return MmioRead8 (PL061EffectiveAddress (Address
, Mask
));
79 MmioWrite8 (PL061EffectiveAddress (Address
, Mask
), Value
);
83 Function implementations
91 // Check if this is a PrimeCell Peripheral
92 if ( (MmioRead8 (PL061_GPIO_PCELL_ID0
) != 0x0D)
93 || (MmioRead8 (PL061_GPIO_PCELL_ID1
) != 0xF0)
94 || (MmioRead8 (PL061_GPIO_PCELL_ID2
) != 0x05)
95 || (MmioRead8 (PL061_GPIO_PCELL_ID3
) != 0xB1)) {
99 // Check if this PrimeCell Peripheral is the PL061 GPIO
100 if ( (MmioRead8 (PL061_GPIO_PERIPH_ID0
) != 0x61)
101 || (MmioRead8 (PL061_GPIO_PERIPH_ID1
) != 0x10)
102 || ((MmioRead8 (PL061_GPIO_PERIPH_ID2
) & 0xF) != 0x04)
103 || (MmioRead8 (PL061_GPIO_PERIPH_ID3
) != 0x00)) {
104 return EFI_NOT_FOUND
;
114 Gets the state of a GPIO pin
118 This - pointer to protocol
119 Gpio - which pin to read
120 Value - state of the pin
124 EFI_SUCCESS - GPIO state returned in Value
125 EFI_INVALID_PARAMETER - Value is NULL pointer or Gpio pin is out of range
130 IN EMBEDDED_GPIO
*This
,
131 IN EMBEDDED_GPIO_PIN Gpio
,
136 || (Gpio
> LAST_GPIO_PIN
))
138 return EFI_INVALID_PARAMETER
;
141 if (PL061GetPins (PL061_GPIO_DATA_REG
, Gpio
)) {
154 Sets the state of a GPIO pin
158 This - pointer to protocol
159 Gpio - which pin to modify
164 EFI_SUCCESS - GPIO set as requested
165 EFI_UNSUPPORTED - Mode is not supported
166 EFI_INVALID_PARAMETER - Gpio pin is out of range
171 IN EMBEDDED_GPIO
*This
,
172 IN EMBEDDED_GPIO_PIN Gpio
,
173 IN EMBEDDED_GPIO_MODE Mode
176 EFI_STATUS Status
= EFI_SUCCESS
;
179 if (Gpio
> LAST_GPIO_PIN
) {
180 Status
= EFI_INVALID_PARAMETER
;
186 case GPIO_MODE_INPUT
:
187 // Set the corresponding direction bit to LOW for input
188 MmioAnd8 (PL061_GPIO_DIR_REG
, ~GPIO_PIN_MASK(Gpio
) & 0xFF);
191 case GPIO_MODE_OUTPUT_0
:
192 // Set the corresponding direction bit to HIGH for output
193 MmioOr8 (PL061_GPIO_DIR_REG
, GPIO_PIN_MASK(Gpio
));
194 // Set the corresponding data bit to LOW for 0
195 PL061SetPins (PL061_GPIO_DATA_REG
, GPIO_PIN_MASK(Gpio
), 0);
198 case GPIO_MODE_OUTPUT_1
:
199 // Set the corresponding direction bit to HIGH for output
200 MmioOr8 (PL061_GPIO_DIR_REG
, GPIO_PIN_MASK(Gpio
));
201 // Set the corresponding data bit to HIGH for 1
202 PL061SetPins (PL061_GPIO_DATA_REG
, GPIO_PIN_MASK(Gpio
), 0xff);
206 // Other modes are not supported
207 return EFI_UNSUPPORTED
;
218 Gets the mode (function) of a GPIO pin
222 This - pointer to protocol
224 Mode - pointer to output mode value
228 EFI_SUCCESS - mode value retrieved
229 EFI_INVALID_PARAMETER - Mode is a null pointer or Gpio pin is out of range
235 IN EMBEDDED_GPIO
*This
,
236 IN EMBEDDED_GPIO_PIN Gpio
,
237 OUT EMBEDDED_GPIO_MODE
*Mode
242 || (Gpio
> LAST_GPIO_PIN
)) {
243 return EFI_INVALID_PARAMETER
;
246 // Check if it is input or output
247 if (MmioRead8 (PL061_GPIO_DIR_REG
) & GPIO_PIN_MASK(Gpio
)) {
249 if (PL061GetPins (PL061_GPIO_DATA_REG
, GPIO_PIN_MASK(Gpio
))) {
250 *Mode
= GPIO_MODE_OUTPUT_1
;
252 *Mode
= GPIO_MODE_OUTPUT_0
;
256 *Mode
= GPIO_MODE_INPUT
;
266 Sets the pull-up / pull-down resistor of a GPIO pin
270 This - pointer to protocol
272 Direction - pull-up, pull-down, or none
276 EFI_UNSUPPORTED - Can not perform the requested operation
282 IN EMBEDDED_GPIO
*This
,
283 IN EMBEDDED_GPIO_PIN Gpio
,
284 IN EMBEDDED_GPIO_PULL Direction
287 return EFI_UNSUPPORTED
;
291 Protocol variable definition
293 EMBEDDED_GPIO gGpio
= {
301 Initialize the state information for the Embedded Gpio protocol.
303 @param ImageHandle of the loaded driver
304 @param SystemTable Pointer to the System Table
306 @retval EFI_SUCCESS Protocol registered
307 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
308 @retval EFI_DEVICE_ERROR Hardware problems
313 PL061InstallProtocol (
314 IN EFI_HANDLE ImageHandle
,
315 IN EFI_SYSTEM_TABLE
*SystemTable
322 // Make sure the Gpio protocol has not been installed in the system yet.
324 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL
, &gEmbeddedGpioProtocolGuid
);
326 Status
= PL061Identify();
327 if (EFI_ERROR(Status
)) {
328 return EFI_DEVICE_ERROR
;
331 // Install the Embedded GPIO Protocol onto a new handle
333 Status
= gBS
->InstallMultipleProtocolInterfaces(
335 &gEmbeddedGpioProtocolGuid
, &gGpio
,
338 if (EFI_ERROR(Status
)) {
339 Status
= EFI_OUT_OF_RESOURCES
;