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