]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPlatformPkg/Drivers/PL061GpioDxe/PL061Gpio.c
ArmPlatformPkg: Add PL061 GPIO driver
[mirror_edk2.git] / ArmPlatformPkg / Drivers / PL061GpioDxe / PL061Gpio.c
CommitLineData
5a62a8b7 1/** @file
2*
3* Copyright (c) 2011, ARM Limited. All rights reserved.
4*
5* This program and the accompanying materials
6* are licensed and made available under the terms and conditions of the BSD License
7* which accompanies this distribution. The full text of the license may be found at
8* http://opensource.org/licenses/bsd-license.php
9*
10* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12*
13**/
14
15
16#include <Base.h>
17#include <PiDxe.h>
18
19#include <Library/BaseLib.h>
20#include <Library/DebugLib.h>
21#include <Library/BaseMemoryLib.h>
22#include <Library/UefiBootServicesTableLib.h>
23#include <Library/UefiRuntimeServicesTableLib.h>
24#include <Library/UefiLib.h>
25#include <Library/IoLib.h>
26
27#include <Protocol/EmbeddedGpio.h>
28#include <ArmPlatform.h>
29#include <Drivers/PL061Gpio.h>
30
31#define LOW_4_BITS 0x0000000F
32
33BOOLEAN mPL061Initialized = FALSE;
34
35/**
36 Function implementations
37**/
38
39EFI_STATUS
40PL061Identify (
41 VOID
42 )
43{
44 // Check if this is a PrimeCell Peripheral
45 if( ( MmioRead8( PL061_GPIO_PCELL_ID0 ) != 0x0D )
46 || ( MmioRead8( PL061_GPIO_PCELL_ID1 ) != 0xF0 )
47 || ( MmioRead8( PL061_GPIO_PCELL_ID2 ) != 0x05 )
48 || ( MmioRead8( PL061_GPIO_PCELL_ID3 ) != 0xB1 ) ) {
49 return EFI_NOT_FOUND;
50 }
51
52 // Check if this PrimeCell Peripheral is the PL061 GPIO
53 if( ( MmioRead8( PL061_GPIO_PERIPH_ID0 ) != 0x61 )
54 || ( MmioRead8( PL061_GPIO_PERIPH_ID1 ) != 0x10 )
55 || ( ( MmioRead8( PL061_GPIO_PERIPH_ID2 ) & LOW_4_BITS ) != 0x04 )
56 || ( MmioRead8( PL061_GPIO_PERIPH_ID3 ) != 0x00 ) ) {
57 return EFI_NOT_FOUND;
58 }
59
60 return EFI_SUCCESS;
61}
62
63EFI_STATUS
64PL061Initialize (
65VOID
66 )
67{
68 EFI_STATUS Status;
69
70 // Check if the PL061 GPIO module exists on board
71 Status = PL061Identify();
72 if (EFI_ERROR( Status )) {
73 Status = EFI_DEVICE_ERROR;
74 goto EXIT;
75 }
76
77 // Do other hardware initialisation things here as required
78
79 // Disable Interrupts
80 //if( MmioRead8( PL061_GPIO_IE_REG ) != 0 ) {
81 // // Ensure interrupts are disabled
82 //}
83
84 mPL061Initialized = TRUE;
85
86 EXIT:
87 return Status;
88}
89
90/**
91
92Routine Description:
93
94 Gets the state of a GPIO pin
95
96Arguments:
97
98 This - pointer to protocol
99 Gpio - which pin to read
100 Value - state of the pin
101
102Returns:
103
104 EFI_SUCCESS - GPIO state returned in Value
105 EFI_INVALID_PARAMETER - Value is NULL pointer or Gpio pin is out of range
106**/
107EFI_STATUS
108EFIAPI
109Get (
110 IN EMBEDDED_GPIO *This,
111 IN EMBEDDED_GPIO_PIN Gpio,
112 OUT UINTN *Value
113 )
114{
115 EFI_STATUS Status = EFI_SUCCESS;
116
117 if( ( Value == NULL )
118 || ( Gpio > LAST_GPIO_PIN ) )
119 {
120 return EFI_INVALID_PARAMETER;
121 }
122
123 // Initialize the hardware if not already done
124 if( !mPL061Initialized ) {
125 Status = PL061Initialize();
126 if( EFI_ERROR(Status) ) {
127 goto EXIT;
128 }
129 }
130
131 if( MmioRead8( PL061_GPIO_DATA_REG ) & GPIO_PIN_MASK_HIGH_8BIT(Gpio) ) {
132 *Value = 1;
133 } else {
134 *Value = 0;
135 }
136
137 EXIT:
138 return Status;
139}
140
141/**
142
143Routine Description:
144
145 Sets the state of a GPIO pin
146
147Arguments:
148
149 This - pointer to protocol
150 Gpio - which pin to modify
151 Mode - mode to set
152
153Returns:
154
155 EFI_SUCCESS - GPIO set as requested
156 EFI_UNSUPPORTED - Mode is not supported
157 EFI_INVALID_PARAMETER - Gpio pin is out of range
158**/
159EFI_STATUS
160EFIAPI
161Set (
162 IN EMBEDDED_GPIO *This,
163 IN EMBEDDED_GPIO_PIN Gpio,
164 IN EMBEDDED_GPIO_MODE Mode
165 )
166{
167 EFI_STATUS Status = EFI_SUCCESS;
168
169 // Check for errors
170 if( Gpio > LAST_GPIO_PIN ) {
171 Status = EFI_INVALID_PARAMETER;
172 goto EXIT;
173 }
174
175 // Initialize the hardware if not already done
176 if( !mPL061Initialized ) {
177 Status = PL061Initialize();
178 if( EFI_ERROR(Status) ) {
179 goto EXIT;
180 }
181 }
182
183 switch (Mode)
184 {
185 case GPIO_MODE_INPUT:
186 // Set the corresponding direction bit to LOW for input
187 MmioAnd8( PL061_GPIO_DIR_REG, GPIO_PIN_MASK_LOW_8BIT(Gpio) );
188 break;
189
190 case GPIO_MODE_OUTPUT_0:
191 // Set the corresponding data bit to LOW for 0
192 MmioAnd8( PL061_GPIO_DATA_REG, GPIO_PIN_MASK_LOW_8BIT(Gpio) );
193 // Set the corresponding direction bit to HIGH for output
194 MmioOr8( PL061_GPIO_DIR_REG, GPIO_PIN_MASK_HIGH_8BIT(Gpio) );
195 break;
196
197 case GPIO_MODE_OUTPUT_1:
198 // Set the corresponding data bit to HIGH for 1
199 MmioOr8( PL061_GPIO_DATA_REG, GPIO_PIN_MASK_HIGH_8BIT(Gpio) );
200 // Set the corresponding direction bit to HIGH for output
201 MmioOr8( PL061_GPIO_DIR_REG, GPIO_PIN_MASK_HIGH_8BIT(Gpio) );
202 break;
203
204 default:
205 // Other modes are not supported
206 return EFI_UNSUPPORTED;
207 }
208
209EXIT:
210 return Status;
211}
212
213/**
214
215Routine Description:
216
217 Gets the mode (function) of a GPIO pin
218
219Arguments:
220
221 This - pointer to protocol
222 Gpio - which pin
223 Mode - pointer to output mode value
224
225Returns:
226
227 EFI_SUCCESS - mode value retrieved
228 EFI_INVALID_PARAMETER - Mode is a null pointer or Gpio pin is out of range
229
230**/
231EFI_STATUS
232EFIAPI
233GetMode (
234 IN EMBEDDED_GPIO *This,
235 IN EMBEDDED_GPIO_PIN Gpio,
236 OUT EMBEDDED_GPIO_MODE *Mode
237 )
238{
239 EFI_STATUS Status;
240
241 // Check for errors
242 if( ( Mode == NULL )
243 || ( Gpio > LAST_GPIO_PIN ) ) {
244 return EFI_INVALID_PARAMETER;
245 }
246
247 // Initialize the hardware if not already done
248 if( !mPL061Initialized ) {
249 Status = PL061Initialize();
250 if( EFI_ERROR(Status) ) {
251 return Status;
252 }
253 }
254
255 // Check if it is input or output
256 if( MmioRead8( PL061_GPIO_DIR_REG ) & GPIO_PIN_MASK_HIGH_8BIT(Gpio) ) {
257 // Pin set to output
258 if( MmioRead8( PL061_GPIO_DATA_REG ) & GPIO_PIN_MASK_HIGH_8BIT(Gpio) ) {
259 *Mode = GPIO_MODE_OUTPUT_1;
260 } else {
261 *Mode = GPIO_MODE_OUTPUT_0;
262 }
263 } else {
264 // Pin set to input
265 *Mode = GPIO_MODE_INPUT;
266 }
267
268 return EFI_SUCCESS;
269}
270
271/**
272
273Routine Description:
274
275 Sets the pull-up / pull-down resistor of a GPIO pin
276
277Arguments:
278
279 This - pointer to protocol
280 Gpio - which pin
281 Direction - pull-up, pull-down, or none
282
283Returns:
284
285 EFI_UNSUPPORTED - Can not perform the requested operation
286
287**/
288EFI_STATUS
289EFIAPI
290SetPull (
291 IN EMBEDDED_GPIO *This,
292 IN EMBEDDED_GPIO_PIN Gpio,
293 IN EMBEDDED_GPIO_PULL Direction
294 )
295{
296 return EFI_UNSUPPORTED;
297}
298
299/**
300 Protocol variable definition
301 **/
302EMBEDDED_GPIO gGpio = {
303 Get,
304 Set,
305 GetMode,
306 SetPull
307};
308
309/**
310 Initialize the state information for the Embedded Gpio protocol.
311
312 @param ImageHandle of the loaded driver
313 @param SystemTable Pointer to the System Table
314
315 @retval EFI_SUCCESS Protocol registered
316 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
317 @retval EFI_DEVICE_ERROR Hardware problems
318
319**/
320EFI_STATUS
321EFIAPI
322PL061InstallProtocol (
323 IN EFI_HANDLE ImageHandle,
324 IN EFI_SYSTEM_TABLE *SystemTable
325 )
326{
327 EFI_STATUS Status;
328 EFI_HANDLE Handle;
329
330 //
331 // Make sure the Gpio protocol has not been installed in the system yet.
332 //
333 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEmbeddedGpioProtocolGuid);
334
335 // Install the Embedded GPIO Protocol onto a new handle
336 Handle = NULL;
337 Status = gBS->InstallMultipleProtocolInterfaces(
338 &Handle,
339 &gEmbeddedGpioProtocolGuid, &gGpio,
340 NULL
341 );
342 if (EFI_ERROR(Status)) {
343 Status = EFI_OUT_OF_RESOURCES;
344 }
345
346 return Status;
347}