TianoCore EDK2 master
Loading...
Searching...
No Matches
PL061Gpio.c
Go to the documentation of this file.
1
10#include <PiDxe.h>
11
12#include <Library/BaseLib.h>
14#include <Library/DebugLib.h>
15#include <Library/IoLib.h>
17#include <Library/PcdLib.h>
19#include <Library/UefiLib.h>
21
23
24#include "PL061Gpio.h"
25
26PLATFORM_GPIO_CONTROLLER *mPL061PlatformGpio;
27
29EFIAPI
30PL061Locate (
31 IN EMBEDDED_GPIO_PIN Gpio,
32 OUT UINTN *ControllerIndex,
33 OUT UINTN *ControllerOffset,
34 OUT UINTN *RegisterBase
35 )
36{
37 UINTN 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
74EFIAPI
75PL061EffectiveAddress (
76 IN UINTN Address,
77 IN UINT8 Mask
78 )
79{
80 return ((Address + PL061_GPIO_DATA_REG_OFFSET) + (UINTN)(Mask << 2));
81}
82
84UINT8
85EFIAPI
86PL061GetPins (
87 IN UINTN Address,
88 IN UINT8 Mask
89 )
90{
91 return MmioRead8 (PL061EffectiveAddress (Address, Mask));
92}
93
95VOID
96EFIAPI
97PL061SetPins (
98 IN UINTN Address,
99 IN UINT8 Mask,
100 IN UINT8 Value
101 )
102{
103 MmioWrite8 (PL061EffectiveAddress (Address, Mask), Value);
104}
105
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
170EFIAPI
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 if (Value == NULL) {
181 return EFI_INVALID_PARAMETER;
182 }
183
184 Status = PL061Locate (Gpio, &Index, &Offset, &RegisterBase);
185 if (EFI_ERROR (Status)) {
186 ASSERT_EFI_ERROR (Status);
187 return Status;
188 }
189
190 if (PL061GetPins (RegisterBase, GPIO_PIN_MASK (Offset)) != 0) {
191 *Value = 1;
192 } else {
193 *Value = 0;
194 }
195
196 return EFI_SUCCESS;
197}
198
218EFIAPI
220 IN EMBEDDED_GPIO *This,
221 IN EMBEDDED_GPIO_PIN Gpio,
222 IN EMBEDDED_GPIO_MODE Mode
223 )
224{
225 EFI_STATUS Status;
226 UINTN Index, Offset, RegisterBase;
227
228 Status = PL061Locate (Gpio, &Index, &Offset, &RegisterBase);
229 if (EFI_ERROR (Status)) {
230 ASSERT_EFI_ERROR (Status);
231 return Status;
232 }
233
234 switch (Mode) {
235 case GPIO_MODE_INPUT:
236 // Set the corresponding direction bit to LOW for input
237 MmioAnd8 (
238 RegisterBase + PL061_GPIO_DIR_REG,
239 ~GPIO_PIN_MASK(Offset) & 0xFF
240 );
241 break;
242
243 case GPIO_MODE_OUTPUT_0:
244 // Set the corresponding direction bit to HIGH for output
245 MmioOr8 (RegisterBase + PL061_GPIO_DIR_REG, GPIO_PIN_MASK (Offset));
246 // Set the corresponding data bit to LOW for 0
247 PL061SetPins (RegisterBase, GPIO_PIN_MASK (Offset), 0);
248 break;
249
250 case GPIO_MODE_OUTPUT_1:
251 // Set the corresponding direction bit to HIGH for output
252 MmioOr8 (RegisterBase + PL061_GPIO_DIR_REG, GPIO_PIN_MASK (Offset));
253 // Set the corresponding data bit to HIGH for 1
254 PL061SetPins (RegisterBase, GPIO_PIN_MASK (Offset), 0xff);
255 break;
256
257 default:
258 // Other modes are not supported
259 return EFI_UNSUPPORTED;
260 }
261
262 return EFI_SUCCESS;
263}
264
284EFIAPI
286 IN EMBEDDED_GPIO *This,
287 IN EMBEDDED_GPIO_PIN Gpio,
288 OUT EMBEDDED_GPIO_MODE *Mode
289 )
290{
291 EFI_STATUS Status;
292 UINTN Index, Offset, RegisterBase;
293
294 // Check for errors
295 if (Mode == NULL) {
296 return EFI_INVALID_PARAMETER;
297 }
298
299 Status = PL061Locate (Gpio, &Index, &Offset, &RegisterBase);
300 if (EFI_ERROR (Status)) {
301 ASSERT_EFI_ERROR (Status);
302 return Status;
303 }
304
305 // Check if it is input or output
306 if (MmioRead8 (RegisterBase + PL061_GPIO_DIR_REG) & GPIO_PIN_MASK (Offset)) {
307 // Pin set to output
308 if (PL061GetPins (RegisterBase, GPIO_PIN_MASK (Offset)) != 0) {
309 *Mode = GPIO_MODE_OUTPUT_1;
310 } else {
311 *Mode = GPIO_MODE_OUTPUT_0;
312 }
313 } else {
314 // Pin set to input
315 *Mode = GPIO_MODE_INPUT;
316 }
317
318 return EFI_SUCCESS;
319}
320
339EFIAPI
341 IN EMBEDDED_GPIO *This,
342 IN EMBEDDED_GPIO_PIN Gpio,
343 IN EMBEDDED_GPIO_PULL Direction
344 )
345{
346 return EFI_UNSUPPORTED;
347}
348
353 Get,
354 Set,
355 GetMode,
356 SetPull
357};
358
371EFIAPI
373 IN EFI_HANDLE ImageHandle,
374 IN EFI_SYSTEM_TABLE *SystemTable
375 )
376{
377 EFI_STATUS Status;
378 EFI_HANDLE Handle;
379 GPIO_CONTROLLER *GpioController;
380
381 //
382 // Make sure the Gpio protocol has not been installed in the system yet.
383 //
384 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEmbeddedGpioProtocolGuid);
385
386 Status = gBS->LocateProtocol (&gPlatformGpioProtocolGuid, NULL, (VOID **)&mPL061PlatformGpio);
387 if (EFI_ERROR (Status) && (Status == EFI_NOT_FOUND)) {
388 // Create the mPL061PlatformGpio
389 mPL061PlatformGpio = (PLATFORM_GPIO_CONTROLLER *)AllocateZeroPool (sizeof (PLATFORM_GPIO_CONTROLLER) + sizeof (GPIO_CONTROLLER));
390 if (mPL061PlatformGpio == NULL) {
391 DEBUG ((DEBUG_ERROR, "%a: failed to allocate PLATFORM_GPIO_CONTROLLER\n", __func__));
392 return EFI_BAD_BUFFER_SIZE;
393 }
394
395 mPL061PlatformGpio->GpioCount = PL061_GPIO_PINS;
396 mPL061PlatformGpio->GpioControllerCount = 1;
397 mPL061PlatformGpio->GpioController = (GPIO_CONTROLLER *)((UINTN)mPL061PlatformGpio + sizeof (PLATFORM_GPIO_CONTROLLER));
398
399 GpioController = mPL061PlatformGpio->GpioController;
400 GpioController->RegisterBase = (UINTN)PcdGet32 (PcdPL061GpioBase);
401 GpioController->GpioIndex = 0;
402 GpioController->InternalGpioCount = PL061_GPIO_PINS;
403 }
404
405 Status = PL061Identify ();
406 if (EFI_ERROR (Status)) {
407 return EFI_DEVICE_ERROR;
408 }
409
410 // Install the Embedded GPIO Protocol onto a new handle
411 Handle = NULL;
412 Status = gBS->InstallMultipleProtocolInterfaces (
413 &Handle,
414 &gEmbeddedGpioProtocolGuid,
415 &gGpio,
416 NULL
417 );
418 if (EFI_ERROR (Status)) {
419 Status = EFI_OUT_OF_RESOURCES;
420 }
421
422 return Status;
423}
UINT64 UINTN
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
UINT8 EFIAPI MmioAnd8(IN UINTN Address, IN UINT8 AndData)
Definition: IoHighLevel.c:1231
UINT8 EFIAPI MmioRead8(IN UINTN Address)
Definition: IoLib.c:82
UINT8 EFIAPI MmioOr8(IN UINTN Address, IN UINT8 OrData)
Definition: IoHighLevel.c:1203
UINT8 EFIAPI MmioWrite8(IN UINTN Address, IN UINT8 Value)
Definition: IoLib.c:126
#define NULL
Definition: Base.h:319
#define STATIC
Definition: Base.h:264
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
#define DEBUG(Expression)
Definition: DebugLib.h:434
#define ASSERT_PROTOCOL_ALREADY_INSTALLED(Handle, Guid)
Definition: DebugLib.h:535
EFI_STATUS PL061Identify(VOID)
Definition: PL061Gpio.c:110
EFI_STATUS EFIAPI Get(IN EMBEDDED_GPIO *This, IN EMBEDDED_GPIO_PIN Gpio, OUT UINTN *Value)
Definition: PL061Gpio.c:171
EFI_STATUS EFIAPI SetPull(IN EMBEDDED_GPIO *This, IN EMBEDDED_GPIO_PIN Gpio, IN EMBEDDED_GPIO_PULL Direction)
Definition: PL061Gpio.c:340
EMBEDDED_GPIO gGpio
Definition: PL061Gpio.c:352
EFI_STATUS EFIAPI PL061InstallProtocol(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
Definition: PL061Gpio.c:372
EFI_STATUS EFIAPI GetMode(IN EMBEDDED_GPIO *This, IN EMBEDDED_GPIO_PIN Gpio, OUT EMBEDDED_GPIO_MODE *Mode)
Definition: PL061Gpio.c:285
EFI_STATUS EFIAPI Set(IN EMBEDDED_GPIO *This, IN EMBEDDED_GPIO_PIN Gpio, IN EMBEDDED_GPIO_MODE Mode)
Definition: PL061Gpio.c:219
#define PcdGet32(TokenName)
Definition: PcdLib.h:362
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_HANDLE
Definition: UefiBaseType.h:33
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_BOOT_SERVICES * gBS