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