]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPlatformPkg/Drivers/PL061GpioDxe/PL061Gpio.c
ArmPlatformPkg: Apply uncrustify changes
[mirror_edk2.git] / ArmPlatformPkg / Drivers / PL061GpioDxe / PL061Gpio.c
CommitLineData
1e57a462 1/** @file\r
5a5440d0
PG
2\r
3 Copyright (c) 2011 - 2020, Arm Limited. All rights reserved.<BR>\r
4 Copyright (c) 2016, Linaro Limited. All rights reserved.\r
5\r
6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
7\r
1e57a462 8**/\r
9\r
1e57a462 10#include <PiDxe.h>\r
11\r
12#include <Library/BaseLib.h>\r
13#include <Library/BaseMemoryLib.h>\r
14#include <Library/DebugLib.h>\r
15#include <Library/IoLib.h>\r
727894d5 16#include <Library/MemoryAllocationLib.h>\r
1e57a462 17#include <Library/PcdLib.h>\r
18#include <Library/UefiBootServicesTableLib.h>\r
19#include <Library/UefiLib.h>\r
20#include <Library/UefiRuntimeServicesTableLib.h>\r
21\r
22#include <Protocol/EmbeddedGpio.h>\r
c13f3665
AB
23\r
24#include "PL061Gpio.h"\r
1e57a462 25\r
40b0b23e 26PLATFORM_GPIO_CONTROLLER *mPL061PlatformGpio;\r
727894d5
HZ
27\r
28EFI_STATUS\r
29EFIAPI\r
30PL061Locate (\r
40b0b23e
MK
31 IN EMBEDDED_GPIO_PIN Gpio,\r
32 OUT UINTN *ControllerIndex,\r
33 OUT UINTN *ControllerOffset,\r
34 OUT UINTN *RegisterBase\r
727894d5
HZ
35 )\r
36{\r
40b0b23e 37 UINT32 Index;\r
727894d5
HZ
38\r
39 for (Index = 0; Index < mPL061PlatformGpio->GpioControllerCount; Index++) {\r
40b0b23e
MK
40 if ( (Gpio >= mPL061PlatformGpio->GpioController[Index].GpioIndex)\r
41 && (Gpio < mPL061PlatformGpio->GpioController[Index].GpioIndex\r
42 + mPL061PlatformGpio->GpioController[Index].InternalGpioCount))\r
43 {\r
44 *ControllerIndex = Index;\r
727894d5 45 *ControllerOffset = Gpio % mPL061PlatformGpio->GpioController[Index].InternalGpioCount;\r
40b0b23e 46 *RegisterBase = mPL061PlatformGpio->GpioController[Index].RegisterBase;\r
727894d5
HZ
47 return EFI_SUCCESS;\r
48 }\r
49 }\r
40b0b23e 50\r
1d2482e1 51 DEBUG ((DEBUG_ERROR, "%a, failed to locate gpio %d\n", __func__, Gpio));\r
727894d5
HZ
52 return EFI_INVALID_PARAMETER;\r
53}\r
54\r
328d8cfa
LL
55//\r
56// The PL061 is a strange beast. The 8-bit data register is aliased across a\r
57// region 0x400 bytes in size, with bits [9:2] of the address operating as a\r
58// mask for both read and write operations:\r
59// For reads:\r
60// - All bits where their corresponding mask bit is 1 return the current\r
61// value of that bit in the GPIO_DATA register.\r
62// - All bits where their corresponding mask bit is 0 return 0.\r
63// For writes:\r
64// - All bits where their corresponding mask bit is 1 set the bit in the\r
65// GPIO_DATA register to the written value.\r
66// - All bits where their corresponding mask bit is 0 are left untouched\r
67// in the GPIO_DATA register.\r
68//\r
69// To keep this driver intelligible, PL061EffectiveAddress, PL061GetPins and\r
70// Pl061SetPins provide an internal abstraction from this interface.\r
71\r
72STATIC\r
73UINTN\r
74EFIAPI\r
75PL061EffectiveAddress (\r
40b0b23e
MK
76 IN UINTN Address,\r
77 IN UINTN Mask\r
328d8cfa
LL
78 )\r
79{\r
80 return ((Address + PL061_GPIO_DATA_REG_OFFSET) + (Mask << 2));\r
81}\r
82\r
83STATIC\r
84UINTN\r
85EFIAPI\r
86PL061GetPins (\r
40b0b23e
MK
87 IN UINTN Address,\r
88 IN UINTN Mask\r
328d8cfa
LL
89 )\r
90{\r
91 return MmioRead8 (PL061EffectiveAddress (Address, Mask));\r
92}\r
93\r
94STATIC\r
95VOID\r
96EFIAPI\r
97PL061SetPins (\r
40b0b23e
MK
98 IN UINTN Address,\r
99 IN UINTN Mask,\r
100 IN UINTN Value\r
328d8cfa
LL
101 )\r
102{\r
103 MmioWrite8 (PL061EffectiveAddress (Address, Mask), Value);\r
104}\r
1e57a462 105\r
106/**\r
107 Function implementations\r
108**/\r
1e57a462 109EFI_STATUS\r
110PL061Identify (\r
111 VOID\r
112 )\r
113{\r
40b0b23e
MK
114 UINTN Index;\r
115 UINTN RegisterBase;\r
727894d5 116\r
40b0b23e
MK
117 if ( (mPL061PlatformGpio->GpioCount == 0)\r
118 || (mPL061PlatformGpio->GpioControllerCount == 0))\r
119 {\r
120 return EFI_NOT_FOUND;\r
1e57a462 121 }\r
122\r
727894d5
HZ
123 for (Index = 0; Index < mPL061PlatformGpio->GpioControllerCount; Index++) {\r
124 if (mPL061PlatformGpio->GpioController[Index].InternalGpioCount != PL061_GPIO_PINS) {\r
125 return EFI_INVALID_PARAMETER;\r
126 }\r
127\r
128 RegisterBase = mPL061PlatformGpio->GpioController[Index].RegisterBase;\r
129\r
130 // Check if this is a PrimeCell Peripheral\r
40b0b23e
MK
131 if ( (MmioRead8 (RegisterBase + PL061_GPIO_PCELL_ID0) != 0x0D)\r
132 || (MmioRead8 (RegisterBase + PL061_GPIO_PCELL_ID1) != 0xF0)\r
133 || (MmioRead8 (RegisterBase + PL061_GPIO_PCELL_ID2) != 0x05)\r
134 || (MmioRead8 (RegisterBase + PL061_GPIO_PCELL_ID3) != 0xB1))\r
135 {\r
727894d5
HZ
136 return EFI_NOT_FOUND;\r
137 }\r
138\r
139 // Check if this PrimeCell Peripheral is the PL061 GPIO\r
40b0b23e
MK
140 if ( (MmioRead8 (RegisterBase + PL061_GPIO_PERIPH_ID0) != 0x61)\r
141 || (MmioRead8 (RegisterBase + PL061_GPIO_PERIPH_ID1) != 0x10)\r
142 || ((MmioRead8 (RegisterBase + PL061_GPIO_PERIPH_ID2) & 0xF) != 0x04)\r
143 || (MmioRead8 (RegisterBase + PL061_GPIO_PERIPH_ID3) != 0x00))\r
144 {\r
727894d5
HZ
145 return EFI_NOT_FOUND;\r
146 }\r
1e57a462 147 }\r
148\r
149 return EFI_SUCCESS;\r
150}\r
151\r
1e57a462 152/**\r
153\r
154Routine Description:\r
155\r
156 Gets the state of a GPIO pin\r
157\r
158Arguments:\r
159\r
160 This - pointer to protocol\r
161 Gpio - which pin to read\r
162 Value - state of the pin\r
163\r
164Returns:\r
165\r
166 EFI_SUCCESS - GPIO state returned in Value\r
167 EFI_INVALID_PARAMETER - Value is NULL pointer or Gpio pin is out of range\r
168**/\r
169EFI_STATUS\r
170EFIAPI\r
171Get (\r
40b0b23e
MK
172 IN EMBEDDED_GPIO *This,\r
173 IN EMBEDDED_GPIO_PIN Gpio,\r
174 OUT UINTN *Value\r
1e57a462 175 )\r
176{\r
40b0b23e
MK
177 EFI_STATUS Status;\r
178 UINTN Index, Offset, RegisterBase;\r
727894d5
HZ
179\r
180 Status = PL061Locate (Gpio, &Index, &Offset, &RegisterBase);\r
181 ASSERT_EFI_ERROR (Status);\r
182\r
183 if (Value == NULL) {\r
1e57a462 184 return EFI_INVALID_PARAMETER;\r
185 }\r
186\r
40b0b23e 187 if (PL061GetPins (RegisterBase, GPIO_PIN_MASK (Offset)) != 0) {\r
1e57a462 188 *Value = 1;\r
189 } else {\r
190 *Value = 0;\r
191 }\r
192\r
2a77a37e 193 return EFI_SUCCESS;\r
1e57a462 194}\r
195\r
196/**\r
197\r
198Routine Description:\r
199\r
200 Sets the state of a GPIO pin\r
201\r
202Arguments:\r
203\r
204 This - pointer to protocol\r
205 Gpio - which pin to modify\r
206 Mode - mode to set\r
207\r
208Returns:\r
209\r
210 EFI_SUCCESS - GPIO set as requested\r
211 EFI_UNSUPPORTED - Mode is not supported\r
212 EFI_INVALID_PARAMETER - Gpio pin is out of range\r
213**/\r
214EFI_STATUS\r
215EFIAPI\r
216Set (\r
217 IN EMBEDDED_GPIO *This,\r
218 IN EMBEDDED_GPIO_PIN Gpio,\r
219 IN EMBEDDED_GPIO_MODE Mode\r
220 )\r
221{\r
40b0b23e
MK
222 EFI_STATUS Status;\r
223 UINTN Index, Offset, RegisterBase;\r
1e57a462 224\r
727894d5
HZ
225 Status = PL061Locate (Gpio, &Index, &Offset, &RegisterBase);\r
226 ASSERT_EFI_ERROR (Status);\r
1e57a462 227\r
40b0b23e 228 switch (Mode) {\r
1e57a462 229 case GPIO_MODE_INPUT:\r
230 // Set the corresponding direction bit to LOW for input\r
40b0b23e
MK
231 MmioAnd8 (\r
232 RegisterBase + PL061_GPIO_DIR_REG,\r
233 ~GPIO_PIN_MASK(Offset) & 0xFF\r
234 );\r
1e57a462 235 break;\r
236\r
237 case GPIO_MODE_OUTPUT_0:\r
1e57a462 238 // Set the corresponding direction bit to HIGH for output\r
40b0b23e 239 MmioOr8 (RegisterBase + PL061_GPIO_DIR_REG, GPIO_PIN_MASK (Offset));\r
328d8cfa 240 // Set the corresponding data bit to LOW for 0\r
40b0b23e 241 PL061SetPins (RegisterBase, GPIO_PIN_MASK (Offset), 0);\r
1e57a462 242 break;\r
243\r
244 case GPIO_MODE_OUTPUT_1:\r
1e57a462 245 // Set the corresponding direction bit to HIGH for output\r
40b0b23e 246 MmioOr8 (RegisterBase + PL061_GPIO_DIR_REG, GPIO_PIN_MASK (Offset));\r
328d8cfa 247 // Set the corresponding data bit to HIGH for 1\r
40b0b23e 248 PL061SetPins (RegisterBase, GPIO_PIN_MASK (Offset), 0xff);\r
727894d5 249 break;\r
1e57a462 250\r
251 default:\r
252 // Other modes are not supported\r
253 return EFI_UNSUPPORTED;\r
254 }\r
255\r
727894d5 256 return EFI_SUCCESS;\r
1e57a462 257}\r
258\r
259/**\r
260\r
261Routine Description:\r
262\r
263 Gets the mode (function) of a GPIO pin\r
264\r
265Arguments:\r
266\r
267 This - pointer to protocol\r
268 Gpio - which pin\r
269 Mode - pointer to output mode value\r
270\r
271Returns:\r
272\r
273 EFI_SUCCESS - mode value retrieved\r
274 EFI_INVALID_PARAMETER - Mode is a null pointer or Gpio pin is out of range\r
275\r
276**/\r
277EFI_STATUS\r
278EFIAPI\r
279GetMode (\r
280 IN EMBEDDED_GPIO *This,\r
281 IN EMBEDDED_GPIO_PIN Gpio,\r
282 OUT EMBEDDED_GPIO_MODE *Mode\r
283 )\r
284{\r
40b0b23e
MK
285 EFI_STATUS Status;\r
286 UINTN Index, Offset, RegisterBase;\r
727894d5
HZ
287\r
288 Status = PL061Locate (Gpio, &Index, &Offset, &RegisterBase);\r
289 ASSERT_EFI_ERROR (Status);\r
290\r
1e57a462 291 // Check for errors\r
727894d5 292 if (Mode == NULL) {\r
1e57a462 293 return EFI_INVALID_PARAMETER;\r
294 }\r
295\r
1e57a462 296 // Check if it is input or output\r
40b0b23e 297 if (MmioRead8 (RegisterBase + PL061_GPIO_DIR_REG) & GPIO_PIN_MASK (Offset)) {\r
1e57a462 298 // Pin set to output\r
40b0b23e 299 if (PL061GetPins (RegisterBase, GPIO_PIN_MASK (Offset)) != 0) {\r
1e57a462 300 *Mode = GPIO_MODE_OUTPUT_1;\r
301 } else {\r
302 *Mode = GPIO_MODE_OUTPUT_0;\r
303 }\r
304 } else {\r
305 // Pin set to input\r
306 *Mode = GPIO_MODE_INPUT;\r
307 }\r
308\r
309 return EFI_SUCCESS;\r
310}\r
311\r
312/**\r
313\r
314Routine Description:\r
315\r
316 Sets the pull-up / pull-down resistor of a GPIO pin\r
317\r
318Arguments:\r
319\r
320 This - pointer to protocol\r
321 Gpio - which pin\r
322 Direction - pull-up, pull-down, or none\r
323\r
324Returns:\r
325\r
326 EFI_UNSUPPORTED - Can not perform the requested operation\r
327\r
328**/\r
329EFI_STATUS\r
330EFIAPI\r
331SetPull (\r
332 IN EMBEDDED_GPIO *This,\r
333 IN EMBEDDED_GPIO_PIN Gpio,\r
334 IN EMBEDDED_GPIO_PULL Direction\r
335 )\r
336{\r
337 return EFI_UNSUPPORTED;\r
338}\r
339\r
340/**\r
341 Protocol variable definition\r
342 **/\r
40b0b23e 343EMBEDDED_GPIO gGpio = {\r
1e57a462 344 Get,\r
345 Set,\r
346 GetMode,\r
347 SetPull\r
348};\r
349\r
350/**\r
351 Initialize the state information for the Embedded Gpio protocol.\r
352\r
353 @param ImageHandle of the loaded driver\r
354 @param SystemTable Pointer to the System Table\r
355\r
356 @retval EFI_SUCCESS Protocol registered\r
357 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure\r
358 @retval EFI_DEVICE_ERROR Hardware problems\r
359\r
360**/\r
361EFI_STATUS\r
362EFIAPI\r
363PL061InstallProtocol (\r
40b0b23e
MK
364 IN EFI_HANDLE ImageHandle,\r
365 IN EFI_SYSTEM_TABLE *SystemTable\r
1e57a462 366 )\r
367{\r
40b0b23e
MK
368 EFI_STATUS Status;\r
369 EFI_HANDLE Handle;\r
370 GPIO_CONTROLLER *GpioController;\r
1e57a462 371\r
372 //\r
373 // Make sure the Gpio protocol has not been installed in the system yet.\r
374 //\r
375 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEmbeddedGpioProtocolGuid);\r
376\r
727894d5
HZ
377 Status = gBS->LocateProtocol (&gPlatformGpioProtocolGuid, NULL, (VOID **)&mPL061PlatformGpio);\r
378 if (EFI_ERROR (Status) && (Status == EFI_NOT_FOUND)) {\r
379 // Create the mPL061PlatformGpio\r
380 mPL061PlatformGpio = (PLATFORM_GPIO_CONTROLLER *)AllocateZeroPool (sizeof (PLATFORM_GPIO_CONTROLLER) + sizeof (GPIO_CONTROLLER));\r
381 if (mPL061PlatformGpio == NULL) {\r
1d2482e1 382 DEBUG ((DEBUG_ERROR, "%a: failed to allocate PLATFORM_GPIO_CONTROLLER\n", __func__));\r
727894d5
HZ
383 return EFI_BAD_BUFFER_SIZE;\r
384 }\r
385\r
40b0b23e 386 mPL061PlatformGpio->GpioCount = PL061_GPIO_PINS;\r
727894d5 387 mPL061PlatformGpio->GpioControllerCount = 1;\r
40b0b23e 388 mPL061PlatformGpio->GpioController = (GPIO_CONTROLLER *)((UINTN)mPL061PlatformGpio + sizeof (PLATFORM_GPIO_CONTROLLER));\r
727894d5 389\r
40b0b23e
MK
390 GpioController = mPL061PlatformGpio->GpioController;\r
391 GpioController->RegisterBase = (UINTN)PcdGet32 (PcdPL061GpioBase);\r
392 GpioController->GpioIndex = 0;\r
727894d5
HZ
393 GpioController->InternalGpioCount = PL061_GPIO_PINS;\r
394 }\r
395\r
40b0b23e
MK
396 Status = PL061Identify ();\r
397 if (EFI_ERROR (Status)) {\r
2a77a37e
LL
398 return EFI_DEVICE_ERROR;\r
399 }\r
400\r
1e57a462 401 // Install the Embedded GPIO Protocol onto a new handle\r
402 Handle = NULL;\r
40b0b23e 403 Status = gBS->InstallMultipleProtocolInterfaces (\r
1e57a462 404 &Handle,\r
40b0b23e
MK
405 &gEmbeddedGpioProtocolGuid,\r
406 &gGpio,\r
1e57a462 407 NULL\r
40b0b23e
MK
408 );\r
409 if (EFI_ERROR (Status)) {\r
1e57a462 410 Status = EFI_OUT_OF_RESOURCES;\r
411 }\r
412\r
413 return Status;\r
414}\r