ArmPlatformPkg: PL061 - only initialize on protocol load
[mirror_edk2.git] / ArmPlatformPkg / Drivers / PL061GpioDxe / PL061Gpio.c
1 /** @file
2 *
3 * Copyright (c) 2011, ARM Limited. All rights reserved.
4 * Copyright (c) 2016, Linaro Limited. All rights reserved.
5 *
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
10 *
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.
13 *
14 **/
15
16
17 #include <PiDxe.h>
18
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>
27
28 #include <Protocol/EmbeddedGpio.h>
29 #include <Drivers/PL061Gpio.h>
30
31
32 /**
33 Function implementations
34 **/
35
36 EFI_STATUS
37 PL061Identify (
38 VOID
39 )
40 {
41 // Check if this is a PrimeCell Peripheral
42 if ( (MmioRead8 (PL061_GPIO_PCELL_ID0) != 0x0D)
43 || (MmioRead8 (PL061_GPIO_PCELL_ID1) != 0xF0)
44 || (MmioRead8 (PL061_GPIO_PCELL_ID2) != 0x05)
45 || (MmioRead8 (PL061_GPIO_PCELL_ID3) != 0xB1)) {
46 return EFI_NOT_FOUND;
47 }
48
49 // Check if this PrimeCell Peripheral is the PL061 GPIO
50 if ( (MmioRead8 (PL061_GPIO_PERIPH_ID0) != 0x61)
51 || (MmioRead8 (PL061_GPIO_PERIPH_ID1) != 0x10)
52 || ((MmioRead8 (PL061_GPIO_PERIPH_ID2) & 0xF) != 0x04)
53 || (MmioRead8 (PL061_GPIO_PERIPH_ID3) != 0x00)) {
54 return EFI_NOT_FOUND;
55 }
56
57 return EFI_SUCCESS;
58 }
59
60 EFI_STATUS
61 PL061Initialize (
62 VOID
63 )
64 {
65 EFI_STATUS Status;
66
67 // Check if the PL061 GPIO module exists on board
68 Status = PL061Identify();
69 if (EFI_ERROR (Status)) {
70 Status = EFI_DEVICE_ERROR;
71 goto EXIT;
72 }
73
74 // Do other hardware initialisation things here as required
75
76 // Disable Interrupts
77 //if (MmioRead8 (PL061_GPIO_IE_REG) != 0) {
78 // // Ensure interrupts are disabled
79 //}
80
81 EXIT:
82 return Status;
83 }
84
85 /**
86
87 Routine Description:
88
89 Gets the state of a GPIO pin
90
91 Arguments:
92
93 This - pointer to protocol
94 Gpio - which pin to read
95 Value - state of the pin
96
97 Returns:
98
99 EFI_SUCCESS - GPIO state returned in Value
100 EFI_INVALID_PARAMETER - Value is NULL pointer or Gpio pin is out of range
101 **/
102 EFI_STATUS
103 EFIAPI
104 Get (
105 IN EMBEDDED_GPIO *This,
106 IN EMBEDDED_GPIO_PIN Gpio,
107 OUT UINTN *Value
108 )
109 {
110 if ( (Value == NULL)
111 || (Gpio > LAST_GPIO_PIN))
112 {
113 return EFI_INVALID_PARAMETER;
114 }
115
116 if (MmioRead8 (PL061_GPIO_DATA_REG) & GPIO_PIN_MASK_HIGH_8BIT(Gpio)) {
117 *Value = 1;
118 } else {
119 *Value = 0;
120 }
121
122 return EFI_SUCCESS;
123 }
124
125 /**
126
127 Routine Description:
128
129 Sets the state of a GPIO pin
130
131 Arguments:
132
133 This - pointer to protocol
134 Gpio - which pin to modify
135 Mode - mode to set
136
137 Returns:
138
139 EFI_SUCCESS - GPIO set as requested
140 EFI_UNSUPPORTED - Mode is not supported
141 EFI_INVALID_PARAMETER - Gpio pin is out of range
142 **/
143 EFI_STATUS
144 EFIAPI
145 Set (
146 IN EMBEDDED_GPIO *This,
147 IN EMBEDDED_GPIO_PIN Gpio,
148 IN EMBEDDED_GPIO_MODE Mode
149 )
150 {
151 EFI_STATUS Status = EFI_SUCCESS;
152
153 // Check for errors
154 if (Gpio > LAST_GPIO_PIN) {
155 Status = EFI_INVALID_PARAMETER;
156 goto EXIT;
157 }
158
159 switch (Mode)
160 {
161 case GPIO_MODE_INPUT:
162 // Set the corresponding direction bit to LOW for input
163 MmioAnd8 (PL061_GPIO_DIR_REG, GPIO_PIN_MASK_LOW_8BIT(Gpio));
164 break;
165
166 case GPIO_MODE_OUTPUT_0:
167 // Set the corresponding data bit to LOW for 0
168 MmioAnd8 (PL061_GPIO_DATA_REG, GPIO_PIN_MASK_LOW_8BIT(Gpio));
169 // Set the corresponding direction bit to HIGH for output
170 MmioOr8 (PL061_GPIO_DIR_REG, GPIO_PIN_MASK_HIGH_8BIT(Gpio));
171 break;
172
173 case GPIO_MODE_OUTPUT_1:
174 // Set the corresponding data bit to HIGH for 1
175 MmioOr8 (PL061_GPIO_DATA_REG, GPIO_PIN_MASK_HIGH_8BIT(Gpio));
176 // Set the corresponding direction bit to HIGH for output
177 MmioOr8 (PL061_GPIO_DIR_REG, GPIO_PIN_MASK_HIGH_8BIT(Gpio));
178 break;
179
180 default:
181 // Other modes are not supported
182 return EFI_UNSUPPORTED;
183 }
184
185 EXIT:
186 return Status;
187 }
188
189 /**
190
191 Routine Description:
192
193 Gets the mode (function) of a GPIO pin
194
195 Arguments:
196
197 This - pointer to protocol
198 Gpio - which pin
199 Mode - pointer to output mode value
200
201 Returns:
202
203 EFI_SUCCESS - mode value retrieved
204 EFI_INVALID_PARAMETER - Mode is a null pointer or Gpio pin is out of range
205
206 **/
207 EFI_STATUS
208 EFIAPI
209 GetMode (
210 IN EMBEDDED_GPIO *This,
211 IN EMBEDDED_GPIO_PIN Gpio,
212 OUT EMBEDDED_GPIO_MODE *Mode
213 )
214 {
215 // Check for errors
216 if ( (Mode == NULL)
217 || (Gpio > LAST_GPIO_PIN)) {
218 return EFI_INVALID_PARAMETER;
219 }
220
221 // Check if it is input or output
222 if (MmioRead8 (PL061_GPIO_DIR_REG) & GPIO_PIN_MASK_HIGH_8BIT(Gpio)) {
223 // Pin set to output
224 if (MmioRead8 (PL061_GPIO_DATA_REG) & GPIO_PIN_MASK_HIGH_8BIT(Gpio)) {
225 *Mode = GPIO_MODE_OUTPUT_1;
226 } else {
227 *Mode = GPIO_MODE_OUTPUT_0;
228 }
229 } else {
230 // Pin set to input
231 *Mode = GPIO_MODE_INPUT;
232 }
233
234 return EFI_SUCCESS;
235 }
236
237 /**
238
239 Routine Description:
240
241 Sets the pull-up / pull-down resistor of a GPIO pin
242
243 Arguments:
244
245 This - pointer to protocol
246 Gpio - which pin
247 Direction - pull-up, pull-down, or none
248
249 Returns:
250
251 EFI_UNSUPPORTED - Can not perform the requested operation
252
253 **/
254 EFI_STATUS
255 EFIAPI
256 SetPull (
257 IN EMBEDDED_GPIO *This,
258 IN EMBEDDED_GPIO_PIN Gpio,
259 IN EMBEDDED_GPIO_PULL Direction
260 )
261 {
262 return EFI_UNSUPPORTED;
263 }
264
265 /**
266 Protocol variable definition
267 **/
268 EMBEDDED_GPIO gGpio = {
269 Get,
270 Set,
271 GetMode,
272 SetPull
273 };
274
275 /**
276 Initialize the state information for the Embedded Gpio protocol.
277
278 @param ImageHandle of the loaded driver
279 @param SystemTable Pointer to the System Table
280
281 @retval EFI_SUCCESS Protocol registered
282 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
283 @retval EFI_DEVICE_ERROR Hardware problems
284
285 **/
286 EFI_STATUS
287 EFIAPI
288 PL061InstallProtocol (
289 IN EFI_HANDLE ImageHandle,
290 IN EFI_SYSTEM_TABLE *SystemTable
291 )
292 {
293 EFI_STATUS Status;
294 EFI_HANDLE Handle;
295
296 //
297 // Make sure the Gpio protocol has not been installed in the system yet.
298 //
299 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEmbeddedGpioProtocolGuid);
300
301 Status = PL061Initialize();
302 if (EFI_ERROR(Status)) {
303 return EFI_DEVICE_ERROR;
304 }
305
306 // Install the Embedded GPIO Protocol onto a new handle
307 Handle = NULL;
308 Status = gBS->InstallMultipleProtocolInterfaces(
309 &Handle,
310 &gEmbeddedGpioProtocolGuid, &gGpio,
311 NULL
312 );
313 if (EFI_ERROR(Status)) {
314 Status = EFI_OUT_OF_RESOURCES;
315 }
316
317 return Status;
318 }