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