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