]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.c
ArmPkg: Apply uncrustify changes
[mirror_edk2.git] / ArmPkg / Drivers / ArmPciCpuIo2Dxe / ArmPciCpuIo2Dxe.c
1 /** @file
2 Produces the CPU I/O 2 Protocol.
3
4 Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>
5 Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
6
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8
9 **/
10
11 #include <PiDxe.h>
12
13 #include <Protocol/CpuIo2.h>
14
15 #include <Library/BaseLib.h>
16 #include <Library/DebugLib.h>
17 #include <Library/IoLib.h>
18 #include <Library/PcdLib.h>
19 #include <Library/UefiBootServicesTableLib.h>
20
21 #define MAX_IO_PORT_ADDRESS 0xFFFF
22
23 //
24 // Handle for the CPU I/O 2 Protocol
25 //
26 STATIC EFI_HANDLE mHandle = NULL;
27
28 //
29 // Lookup table for increment values based on transfer widths
30 //
31 STATIC CONST UINT8 mInStride[] = {
32 1, // EfiCpuIoWidthUint8
33 2, // EfiCpuIoWidthUint16
34 4, // EfiCpuIoWidthUint32
35 8, // EfiCpuIoWidthUint64
36 0, // EfiCpuIoWidthFifoUint8
37 0, // EfiCpuIoWidthFifoUint16
38 0, // EfiCpuIoWidthFifoUint32
39 0, // EfiCpuIoWidthFifoUint64
40 1, // EfiCpuIoWidthFillUint8
41 2, // EfiCpuIoWidthFillUint16
42 4, // EfiCpuIoWidthFillUint32
43 8 // EfiCpuIoWidthFillUint64
44 };
45
46 //
47 // Lookup table for increment values based on transfer widths
48 //
49 STATIC CONST UINT8 mOutStride[] = {
50 1, // EfiCpuIoWidthUint8
51 2, // EfiCpuIoWidthUint16
52 4, // EfiCpuIoWidthUint32
53 8, // EfiCpuIoWidthUint64
54 1, // EfiCpuIoWidthFifoUint8
55 2, // EfiCpuIoWidthFifoUint16
56 4, // EfiCpuIoWidthFifoUint32
57 8, // EfiCpuIoWidthFifoUint64
58 0, // EfiCpuIoWidthFillUint8
59 0, // EfiCpuIoWidthFillUint16
60 0, // EfiCpuIoWidthFillUint32
61 0 // EfiCpuIoWidthFillUint64
62 };
63
64 /**
65 Check parameters to a CPU I/O 2 Protocol service request.
66
67 The I/O operations are carried out exactly as requested. The caller is responsible
68 for satisfying any alignment and I/O width restrictions that a PI System on a
69 platform might require. For example on some platforms, width requests of
70 EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
71 be handled by the driver.
72
73 @param[in] MmioOperation TRUE for an MMIO operation, FALSE for I/O Port operation.
74 @param[in] Width Signifies the width of the I/O or Memory operation.
75 @param[in] Address The base address of the I/O operation.
76 @param[in] Count The number of I/O operations to perform. The number of
77 bytes moved is Width size * Count, starting at Address.
78 @param[in] Buffer For read operations, the destination buffer to store the results.
79 For write operations, the source buffer from which to write data.
80
81 @retval EFI_SUCCESS The parameters for this request pass the checks.
82 @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
83 @retval EFI_INVALID_PARAMETER Buffer is NULL.
84 @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
85 @retval EFI_UNSUPPORTED The address range specified by Address, Width,
86 and Count is not valid for this PI system.
87
88 **/
89 STATIC
90 EFI_STATUS
91 CpuIoCheckParameter (
92 IN BOOLEAN MmioOperation,
93 IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
94 IN UINT64 Address,
95 IN UINTN Count,
96 IN VOID *Buffer
97 )
98 {
99 UINT64 MaxCount;
100 UINT64 Limit;
101
102 //
103 // Check to see if Buffer is NULL
104 //
105 if (Buffer == NULL) {
106 return EFI_INVALID_PARAMETER;
107 }
108
109 //
110 // Check to see if Width is in the valid range
111 //
112 if ((UINT32)Width >= EfiCpuIoWidthMaximum) {
113 return EFI_INVALID_PARAMETER;
114 }
115
116 //
117 // For FIFO type, the target address won't increase during the access,
118 // so treat Count as 1
119 //
120 if ((Width >= EfiCpuIoWidthFifoUint8) && (Width <= EfiCpuIoWidthFifoUint64)) {
121 Count = 1;
122 }
123
124 //
125 // Check to see if Width is in the valid range for I/O Port operations
126 //
127 Width = (EFI_CPU_IO_PROTOCOL_WIDTH)(Width & 0x03);
128 if (!MmioOperation && (Width == EfiCpuIoWidthUint64)) {
129 return EFI_INVALID_PARAMETER;
130 }
131
132 //
133 // Check to see if Address is aligned
134 //
135 if ((Address & (UINT64)(mInStride[Width] - 1)) != 0) {
136 return EFI_UNSUPPORTED;
137 }
138
139 //
140 // Check to see if any address associated with this transfer exceeds the maximum
141 // allowed address. The maximum address implied by the parameters passed in is
142 // Address + Size * Count. If the following condition is met, then the transfer
143 // is not supported.
144 //
145 // Address + Size * Count > (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS) + 1
146 //
147 // Since MAX_ADDRESS can be the maximum integer value supported by the CPU and Count
148 // can also be the maximum integer value supported by the CPU, this range
149 // check must be adjusted to avoid all overflow conditions.
150 //
151 // The following form of the range check is equivalent but assumes that
152 // MAX_ADDRESS and MAX_IO_PORT_ADDRESS are of the form (2^n - 1).
153 //
154 Limit = (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS);
155 if (Count == 0) {
156 if (Address > Limit) {
157 return EFI_UNSUPPORTED;
158 }
159 } else {
160 MaxCount = RShiftU64 (Limit, Width);
161 if (MaxCount < (Count - 1)) {
162 return EFI_UNSUPPORTED;
163 }
164
165 if (Address > LShiftU64 (MaxCount - Count + 1, Width)) {
166 return EFI_UNSUPPORTED;
167 }
168 }
169
170 //
171 // Check to see if Buffer is aligned
172 //
173 if (((UINTN)Buffer & ((MIN (sizeof (UINTN), mInStride[Width]) - 1))) != 0) {
174 return EFI_UNSUPPORTED;
175 }
176
177 return EFI_SUCCESS;
178 }
179
180 /**
181 Reads memory-mapped registers.
182
183 The I/O operations are carried out exactly as requested. The caller is responsible
184 for satisfying any alignment and I/O width restrictions that a PI System on a
185 platform might require. For example on some platforms, width requests of
186 EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
187 be handled by the driver.
188
189 If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
190 or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
191 each of the Count operations that is performed.
192
193 If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
194 EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
195 incremented for each of the Count operations that is performed. The read or
196 write operation is performed Count times on the same Address.
197
198 If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
199 EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
200 incremented for each of the Count operations that is performed. The read or
201 write operation is performed Count times from the first element of Buffer.
202
203 @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance.
204 @param[in] Width Signifies the width of the I/O or Memory operation.
205 @param[in] Address The base address of the I/O operation.
206 @param[in] Count The number of I/O operations to perform. The number of
207 bytes moved is Width size * Count, starting at Address.
208 @param[out] Buffer For read operations, the destination buffer to store the results.
209 For write operations, the source buffer from which to write data.
210
211 @retval EFI_SUCCESS The data was read from or written to the PI system.
212 @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
213 @retval EFI_INVALID_PARAMETER Buffer is NULL.
214 @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
215 @retval EFI_UNSUPPORTED The address range specified by Address, Width,
216 and Count is not valid for this PI system.
217
218 **/
219 STATIC
220 EFI_STATUS
221 EFIAPI
222 CpuMemoryServiceRead (
223 IN EFI_CPU_IO2_PROTOCOL *This,
224 IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
225 IN UINT64 Address,
226 IN UINTN Count,
227 OUT VOID *Buffer
228 )
229 {
230 EFI_STATUS Status;
231 UINT8 InStride;
232 UINT8 OutStride;
233 EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth;
234 UINT8 *Uint8Buffer;
235
236 Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer);
237 if (EFI_ERROR (Status)) {
238 return Status;
239 }
240
241 //
242 // Select loop based on the width of the transfer
243 //
244 InStride = mInStride[Width];
245 OutStride = mOutStride[Width];
246 OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH)(Width & 0x03);
247 for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
248 if (OperationWidth == EfiCpuIoWidthUint8) {
249 *Uint8Buffer = MmioRead8 ((UINTN)Address);
250 } else if (OperationWidth == EfiCpuIoWidthUint16) {
251 *((UINT16 *)Uint8Buffer) = MmioRead16 ((UINTN)Address);
252 } else if (OperationWidth == EfiCpuIoWidthUint32) {
253 *((UINT32 *)Uint8Buffer) = MmioRead32 ((UINTN)Address);
254 } else if (OperationWidth == EfiCpuIoWidthUint64) {
255 *((UINT64 *)Uint8Buffer) = MmioRead64 ((UINTN)Address);
256 }
257 }
258
259 return EFI_SUCCESS;
260 }
261
262 /**
263 Writes memory-mapped registers.
264
265 The I/O operations are carried out exactly as requested. The caller is responsible
266 for satisfying any alignment and I/O width restrictions that a PI System on a
267 platform might require. For example on some platforms, width requests of
268 EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
269 be handled by the driver.
270
271 If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
272 or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
273 each of the Count operations that is performed.
274
275 If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
276 EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
277 incremented for each of the Count operations that is performed. The read or
278 write operation is performed Count times on the same Address.
279
280 If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
281 EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
282 incremented for each of the Count operations that is performed. The read or
283 write operation is performed Count times from the first element of Buffer.
284
285 @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance.
286 @param[in] Width Signifies the width of the I/O or Memory operation.
287 @param[in] Address The base address of the I/O operation.
288 @param[in] Count The number of I/O operations to perform. The number of
289 bytes moved is Width size * Count, starting at Address.
290 @param[in] Buffer For read operations, the destination buffer to store the results.
291 For write operations, the source buffer from which to write data.
292
293 @retval EFI_SUCCESS The data was read from or written to the PI system.
294 @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
295 @retval EFI_INVALID_PARAMETER Buffer is NULL.
296 @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
297 @retval EFI_UNSUPPORTED The address range specified by Address, Width,
298 and Count is not valid for this PI system.
299
300 **/
301 STATIC
302 EFI_STATUS
303 EFIAPI
304 CpuMemoryServiceWrite (
305 IN EFI_CPU_IO2_PROTOCOL *This,
306 IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
307 IN UINT64 Address,
308 IN UINTN Count,
309 IN VOID *Buffer
310 )
311 {
312 EFI_STATUS Status;
313 UINT8 InStride;
314 UINT8 OutStride;
315 EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth;
316 UINT8 *Uint8Buffer;
317
318 Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer);
319 if (EFI_ERROR (Status)) {
320 return Status;
321 }
322
323 //
324 // Select loop based on the width of the transfer
325 //
326 InStride = mInStride[Width];
327 OutStride = mOutStride[Width];
328 OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH)(Width & 0x03);
329 for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
330 if (OperationWidth == EfiCpuIoWidthUint8) {
331 MmioWrite8 ((UINTN)Address, *Uint8Buffer);
332 } else if (OperationWidth == EfiCpuIoWidthUint16) {
333 MmioWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer));
334 } else if (OperationWidth == EfiCpuIoWidthUint32) {
335 MmioWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer));
336 } else if (OperationWidth == EfiCpuIoWidthUint64) {
337 MmioWrite64 ((UINTN)Address, *((UINT64 *)Uint8Buffer));
338 }
339 }
340
341 return EFI_SUCCESS;
342 }
343
344 /**
345 Reads I/O registers.
346
347 The I/O operations are carried out exactly as requested. The caller is responsible
348 for satisfying any alignment and I/O width restrictions that a PI System on a
349 platform might require. For example on some platforms, width requests of
350 EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
351 be handled by the driver.
352
353 If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
354 or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
355 each of the Count operations that is performed.
356
357 If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
358 EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
359 incremented for each of the Count operations that is performed. The read or
360 write operation is performed Count times on the same Address.
361
362 If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
363 EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
364 incremented for each of the Count operations that is performed. The read or
365 write operation is performed Count times from the first element of Buffer.
366
367 @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance.
368 @param[in] Width Signifies the width of the I/O or Memory operation.
369 @param[in] Address The base address of the I/O operation.
370 @param[in] Count The number of I/O operations to perform. The number of
371 bytes moved is Width size * Count, starting at Address.
372 @param[out] Buffer For read operations, the destination buffer to store the results.
373 For write operations, the source buffer from which to write data.
374
375 @retval EFI_SUCCESS The data was read from or written to the PI system.
376 @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
377 @retval EFI_INVALID_PARAMETER Buffer is NULL.
378 @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
379 @retval EFI_UNSUPPORTED The address range specified by Address, Width,
380 and Count is not valid for this PI system.
381
382 **/
383 STATIC
384 EFI_STATUS
385 EFIAPI
386 CpuIoServiceRead (
387 IN EFI_CPU_IO2_PROTOCOL *This,
388 IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
389 IN UINT64 Address,
390 IN UINTN Count,
391 OUT VOID *Buffer
392 )
393 {
394 EFI_STATUS Status;
395 UINT8 InStride;
396 UINT8 OutStride;
397 EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth;
398 UINT8 *Uint8Buffer;
399
400 Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer);
401 if (EFI_ERROR (Status)) {
402 return Status;
403 }
404
405 Address += PcdGet64 (PcdPciIoTranslation);
406
407 //
408 // Select loop based on the width of the transfer
409 //
410 InStride = mInStride[Width];
411 OutStride = mOutStride[Width];
412 OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH)(Width & 0x03);
413
414 for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
415 if (OperationWidth == EfiCpuIoWidthUint8) {
416 *Uint8Buffer = MmioRead8 ((UINTN)Address);
417 } else if (OperationWidth == EfiCpuIoWidthUint16) {
418 *((UINT16 *)Uint8Buffer) = MmioRead16 ((UINTN)Address);
419 } else if (OperationWidth == EfiCpuIoWidthUint32) {
420 *((UINT32 *)Uint8Buffer) = MmioRead32 ((UINTN)Address);
421 }
422 }
423
424 return EFI_SUCCESS;
425 }
426
427 /**
428 Write I/O registers.
429
430 The I/O operations are carried out exactly as requested. The caller is responsible
431 for satisfying any alignment and I/O width restrictions that a PI System on a
432 platform might require. For example on some platforms, width requests of
433 EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
434 be handled by the driver.
435
436 If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
437 or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
438 each of the Count operations that is performed.
439
440 If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
441 EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
442 incremented for each of the Count operations that is performed. The read or
443 write operation is performed Count times on the same Address.
444
445 If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
446 EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
447 incremented for each of the Count operations that is performed. The read or
448 write operation is performed Count times from the first element of Buffer.
449
450 @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance.
451 @param[in] Width Signifies the width of the I/O or Memory operation.
452 @param[in] Address The base address of the I/O operation.
453 @param[in] Count The number of I/O operations to perform. The number of
454 bytes moved is Width size * Count, starting at Address.
455 @param[in] Buffer For read operations, the destination buffer to store the results.
456 For write operations, the source buffer from which to write data.
457
458 @retval EFI_SUCCESS The data was read from or written to the PI system.
459 @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
460 @retval EFI_INVALID_PARAMETER Buffer is NULL.
461 @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
462 @retval EFI_UNSUPPORTED The address range specified by Address, Width,
463 and Count is not valid for this PI system.
464
465 **/
466 STATIC
467 EFI_STATUS
468 EFIAPI
469 CpuIoServiceWrite (
470 IN EFI_CPU_IO2_PROTOCOL *This,
471 IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
472 IN UINT64 Address,
473 IN UINTN Count,
474 IN VOID *Buffer
475 )
476 {
477 EFI_STATUS Status;
478 UINT8 InStride;
479 UINT8 OutStride;
480 EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth;
481 UINT8 *Uint8Buffer;
482
483 //
484 // Make sure the parameters are valid
485 //
486 Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer);
487 if (EFI_ERROR (Status)) {
488 return Status;
489 }
490
491 Address += PcdGet64 (PcdPciIoTranslation);
492
493 //
494 // Select loop based on the width of the transfer
495 //
496 InStride = mInStride[Width];
497 OutStride = mOutStride[Width];
498 OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH)(Width & 0x03);
499
500 for (Uint8Buffer = (UINT8 *)Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
501 if (OperationWidth == EfiCpuIoWidthUint8) {
502 MmioWrite8 ((UINTN)Address, *Uint8Buffer);
503 } else if (OperationWidth == EfiCpuIoWidthUint16) {
504 MmioWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer));
505 } else if (OperationWidth == EfiCpuIoWidthUint32) {
506 MmioWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer));
507 }
508 }
509
510 return EFI_SUCCESS;
511 }
512
513 //
514 // CPU I/O 2 Protocol instance
515 //
516 STATIC EFI_CPU_IO2_PROTOCOL mCpuIo2 = {
517 {
518 CpuMemoryServiceRead,
519 CpuMemoryServiceWrite
520 },
521 {
522 CpuIoServiceRead,
523 CpuIoServiceWrite
524 }
525 };
526
527 /**
528 The user Entry Point for module CpuIo2Dxe. The user code starts with this function.
529
530 @param[in] ImageHandle The firmware allocated handle for the EFI image.
531 @param[in] SystemTable A pointer to the EFI System Table.
532
533 @retval EFI_SUCCESS The entry point is executed successfully.
534 @retval other Some error occurs when executing this entry point.
535
536 **/
537 EFI_STATUS
538 EFIAPI
539 ArmPciCpuIo2Initialize (
540 IN EFI_HANDLE ImageHandle,
541 IN EFI_SYSTEM_TABLE *SystemTable
542 )
543 {
544 EFI_STATUS Status;
545
546 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiCpuIo2ProtocolGuid);
547 Status = gBS->InstallMultipleProtocolInterfaces (
548 &mHandle,
549 &gEfiCpuIo2ProtocolGuid,
550 &mCpuIo2,
551 NULL
552 );
553 ASSERT_EFI_ERROR (Status);
554
555 return Status;
556 }