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