]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/PciEmulation.c
e908953c0e4f265ebbb1b300cf5e219fc2b9bfff
[mirror_edk2.git] / ArmPlatformPkg / ArmJunoPkg / Drivers / ArmJunoDxe / PciEmulation.c
1 /** @file
2
3 Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
4 Copyright (c) 2013 - 2014, ARM Ltd. All rights reserved.<BR>
5
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include "PciEmulation.h"
17
18 #define HOST_CONTROLLER_OPERATION_REG_SIZE 0x44
19
20 typedef struct {
21 ACPI_HID_DEVICE_PATH AcpiDevicePath;
22 PCI_DEVICE_PATH PciDevicePath;
23 EFI_DEVICE_PATH_PROTOCOL EndDevicePath;
24 } EFI_PCI_IO_DEVICE_PATH;
25
26 typedef struct {
27 UINT32 Signature;
28 EFI_PCI_IO_DEVICE_PATH DevicePath;
29 EFI_PCI_IO_PROTOCOL PciIoProtocol;
30 PCI_TYPE00 *ConfigSpace;
31 PCI_ROOT_BRIDGE RootBridge;
32 UINTN Segment;
33 } EFI_PCI_IO_PRIVATE_DATA;
34
35 #define EFI_PCI_IO_PRIVATE_DATA_SIGNATURE SIGNATURE_32('p', 'c', 'i', 'o')
36 #define EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(a) CR (a, EFI_PCI_IO_PRIVATE_DATA, PciIoProtocol, EFI_PCI_IO_PRIVATE_DATA_SIGNATURE)
37
38 EFI_PCI_IO_DEVICE_PATH PciIoDevicePathTemplate =
39 {
40 {
41 { ACPI_DEVICE_PATH, ACPI_DP, { sizeof (ACPI_HID_DEVICE_PATH), 0 } },
42 EISA_PNP_ID(0x0A03), // HID
43 0 // UID
44 },
45 {
46 { HARDWARE_DEVICE_PATH, HW_PCI_DP, { sizeof (PCI_DEVICE_PATH), 0 } },
47 0,
48 0
49 },
50 { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0} }
51 };
52
53 STATIC
54 VOID
55 ConfigureUSBHost (
56 VOID
57 )
58 {
59 }
60
61
62 EFI_STATUS
63 PciIoPollMem (
64 IN EFI_PCI_IO_PROTOCOL *This,
65 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
66 IN UINT8 BarIndex,
67 IN UINT64 Offset,
68 IN UINT64 Mask,
69 IN UINT64 Value,
70 IN UINT64 Delay,
71 OUT UINT64 *Result
72 )
73 {
74 ASSERT (FALSE);
75 return EFI_UNSUPPORTED;
76 }
77
78 EFI_STATUS
79 PciIoPollIo (
80 IN EFI_PCI_IO_PROTOCOL *This,
81 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
82 IN UINT8 BarIndex,
83 IN UINT64 Offset,
84 IN UINT64 Mask,
85 IN UINT64 Value,
86 IN UINT64 Delay,
87 OUT UINT64 *Result
88 )
89 {
90 ASSERT (FALSE);
91 return EFI_UNSUPPORTED;
92 }
93
94 EFI_STATUS
95 PciIoMemRead (
96 IN EFI_PCI_IO_PROTOCOL *This,
97 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
98 IN UINT8 BarIndex,
99 IN UINT64 Offset,
100 IN UINTN Count,
101 IN OUT VOID *Buffer
102 )
103 {
104 EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS (This);
105
106 return PciRootBridgeIoMemRead (&Private->RootBridge.Io,
107 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
108 Private->ConfigSpace->Device.Bar[BarIndex] + Offset, //Fix me ConfigSpace
109 Count,
110 Buffer
111 );
112 }
113
114 EFI_STATUS
115 PciIoMemWrite (
116 IN EFI_PCI_IO_PROTOCOL *This,
117 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
118 IN UINT8 BarIndex,
119 IN UINT64 Offset,
120 IN UINTN Count,
121 IN OUT VOID *Buffer
122 )
123 {
124 EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS (This);
125
126 return PciRootBridgeIoMemWrite (&Private->RootBridge.Io,
127 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
128 Private->ConfigSpace->Device.Bar[BarIndex] + Offset, //Fix me ConfigSpace
129 Count,
130 Buffer
131 );
132 }
133
134 EFI_STATUS
135 PciIoIoRead (
136 IN EFI_PCI_IO_PROTOCOL *This,
137 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
138 IN UINT8 BarIndex,
139 IN UINT64 Offset,
140 IN UINTN Count,
141 IN OUT VOID *Buffer
142 )
143 {
144 ASSERT (FALSE);
145 return EFI_UNSUPPORTED;
146 }
147
148 EFI_STATUS
149 PciIoIoWrite (
150 IN EFI_PCI_IO_PROTOCOL *This,
151 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
152 IN UINT8 BarIndex,
153 IN UINT64 Offset,
154 IN UINTN Count,
155 IN OUT VOID *Buffer
156 )
157 {
158 ASSERT (FALSE);
159 return EFI_UNSUPPORTED;
160 }
161
162 /**
163 Enable a PCI driver to read PCI controller registers in PCI configuration space.
164
165 @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance.
166 @param[in] Width Signifies the width of the memory operations.
167 @param[in] Offset The offset within the PCI configuration space for
168 the PCI controller.
169 @param[in] Count The number of PCI configuration operations to
170 perform. Bytes moved is Width size * Count,
171 starting at Offset.
172
173 @param[in out] Buffer The destination buffer to store the results.
174
175 @retval EFI_SUCCESS The data was read from the PCI controller.
176 @retval EFI_INVALID_PARAMETER "Width" is invalid.
177 @retval EFI_INVALID_PARAMETER "Buffer" is NULL.
178
179 **/
180 EFI_STATUS
181 PciIoPciRead (
182 IN EFI_PCI_IO_PROTOCOL *This,
183 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
184 IN UINT32 Offset,
185 IN UINTN Count,
186 IN OUT VOID *Buffer
187 )
188 {
189 EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS (This);
190 EFI_STATUS Status;
191
192 if ((Width < 0) || (Width >= EfiPciIoWidthMaximum) || (Buffer == NULL)) {
193 return EFI_INVALID_PARAMETER;
194 }
195
196 Status = PciRootBridgeIoMemRW (
197 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)Width,
198 Count,
199 TRUE,
200 (PTR)(UINTN)Buffer,
201 TRUE,
202 (PTR)(UINTN)(((UINT8 *)Private->ConfigSpace) + Offset) //Fix me ConfigSpace
203 );
204
205 return Status;
206 }
207
208 /**
209 Enable a PCI driver to write PCI controller registers in PCI configuration space.
210
211 @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance.
212 @param[in] Width Signifies the width of the memory operations.
213 @param[in] Offset The offset within the PCI configuration space for
214 the PCI controller.
215 @param[in] Count The number of PCI configuration operations to
216 perform. Bytes moved is Width size * Count,
217 starting at Offset.
218
219 @param[in out] Buffer The source buffer to write data from.
220
221 @retval EFI_SUCCESS The data was read from the PCI controller.
222 @retval EFI_INVALID_PARAMETER "Width" is invalid.
223 @retval EFI_INVALID_PARAMETER "Buffer" is NULL.
224
225 **/
226 EFI_STATUS
227 PciIoPciWrite (
228 IN EFI_PCI_IO_PROTOCOL *This,
229 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
230 IN UINT32 Offset,
231 IN UINTN Count,
232 IN OUT VOID *Buffer
233 )
234 {
235 EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS (This);
236
237 if ((Width < 0) || (Width >= EfiPciIoWidthMaximum) || (Buffer == NULL)) {
238 return EFI_INVALID_PARAMETER;
239 }
240
241 return PciRootBridgeIoMemRW ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
242 Count,
243 TRUE,
244 (PTR)(UINTN)(((UINT8 *)Private->ConfigSpace) + Offset), //Fix me ConfigSpace
245 TRUE,
246 (PTR)(UINTN)Buffer
247 );
248 }
249
250 EFI_STATUS
251 PciIoCopyMem (
252 IN EFI_PCI_IO_PROTOCOL *This,
253 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
254 IN UINT8 DestBarIndex,
255 IN UINT64 DestOffset,
256 IN UINT8 SrcBarIndex,
257 IN UINT64 SrcOffset,
258 IN UINTN Count
259 )
260 {
261 ASSERT (FALSE);
262 return EFI_UNSUPPORTED;
263 }
264
265 EFI_STATUS
266 PciIoMap (
267 IN EFI_PCI_IO_PROTOCOL *This,
268 IN EFI_PCI_IO_PROTOCOL_OPERATION Operation,
269 IN VOID *HostAddress,
270 IN OUT UINTN *NumberOfBytes,
271 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
272 OUT VOID **Mapping
273 )
274 {
275 DMA_MAP_OPERATION DmaOperation;
276
277 if (Operation == EfiPciIoOperationBusMasterRead) {
278 DmaOperation = MapOperationBusMasterRead;
279 } else if (Operation == EfiPciIoOperationBusMasterWrite) {
280 DmaOperation = MapOperationBusMasterWrite;
281 } else if (Operation == EfiPciIoOperationBusMasterCommonBuffer) {
282 DmaOperation = MapOperationBusMasterCommonBuffer;
283 } else {
284 return EFI_INVALID_PARAMETER;
285 }
286 return DmaMap (DmaOperation, HostAddress, NumberOfBytes, DeviceAddress, Mapping);
287 }
288
289 EFI_STATUS
290 PciIoUnmap (
291 IN EFI_PCI_IO_PROTOCOL *This,
292 IN VOID *Mapping
293 )
294 {
295 return DmaUnmap (Mapping);
296 }
297
298 /**
299 Allocate pages that are suitable for an EfiPciIoOperationBusMasterCommonBuffer
300 mapping.
301
302 @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance.
303 @param[in] Type This parameter is not used and must be ignored.
304 @param[in] MemoryType The type of memory to allocate, EfiBootServicesData or
305 EfiRuntimeServicesData.
306 @param[in] Pages The number of pages to allocate.
307 @param[out] HostAddress A pointer to store the base system memory address of
308 the allocated range.
309 @param[in] Attributes The requested bit mask of attributes for the allocated
310 range. Only the attributes,
311 EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE and
312 EFI_PCI_ATTRIBUTE_MEMORY_CACHED may be used with this
313 function. If any other bits are set, then EFI_UNSUPPORTED
314 is returned. This function ignores this bit mask.
315
316 @retval EFI_SUCCESS The requested memory pages were allocated.
317 @retval EFI_INVALID_PARAMETER HostAddress is NULL.
318 @retval EFI_INVALID_PARAMETER MemoryType is invalid.
319 @retval EFI_UNSUPPORTED Attributes is unsupported.
320 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
321
322 **/
323 EFI_STATUS
324 PciIoAllocateBuffer (
325 IN EFI_PCI_IO_PROTOCOL *This,
326 IN EFI_ALLOCATE_TYPE Type,
327 IN EFI_MEMORY_TYPE MemoryType,
328 IN UINTN Pages,
329 OUT VOID **HostAddress,
330 IN UINT64 Attributes
331 )
332 {
333 if (Attributes &
334 (~(EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE |
335 EFI_PCI_ATTRIBUTE_MEMORY_CACHED ))) {
336 return EFI_UNSUPPORTED;
337 }
338
339 return DmaAllocateBuffer (MemoryType, Pages, HostAddress);
340 }
341
342
343 EFI_STATUS
344 PciIoFreeBuffer (
345 IN EFI_PCI_IO_PROTOCOL *This,
346 IN UINTN Pages,
347 IN VOID *HostAddress
348 )
349 {
350 return DmaFreeBuffer (Pages, HostAddress);
351 }
352
353
354 EFI_STATUS
355 PciIoFlush (
356 IN EFI_PCI_IO_PROTOCOL *This
357 )
358 {
359 return EFI_SUCCESS;
360 }
361
362 /**
363 Retrieves this PCI controller's current PCI bus number, device number, and function number.
364
365 @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance.
366 @param[out] SegmentNumber The PCI controller's current PCI segment number.
367 @param[out] BusNumber The PCI controller's current PCI bus number.
368 @param[out] DeviceNumber The PCI controller's current PCI device number.
369 @param[out] FunctionNumber The PCI controller’s current PCI function number.
370
371 @retval EFI_SUCCESS The PCI controller location was returned.
372 @retval EFI_INVALID_PARAMETER At least one out of the four output parameters is
373 a NULL pointer.
374 **/
375 EFI_STATUS
376 PciIoGetLocation (
377 IN EFI_PCI_IO_PROTOCOL *This,
378 OUT UINTN *SegmentNumber,
379 OUT UINTN *BusNumber,
380 OUT UINTN *DeviceNumber,
381 OUT UINTN *FunctionNumber
382 )
383 {
384 EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS (This);
385
386 if ((SegmentNumber == NULL) || (BusNumber == NULL) ||
387 (DeviceNumber == NULL) || (FunctionNumber == NULL) ) {
388 return EFI_INVALID_PARAMETER;
389 }
390
391 *SegmentNumber = Private->Segment;
392 *BusNumber = 0xff;
393 *DeviceNumber = 0;
394 *FunctionNumber = 0;
395
396 return EFI_SUCCESS;
397 }
398
399 /**
400 Performs an operation on the attributes that this PCI controller supports.
401
402 The operations include getting the set of supported attributes, retrieving
403 the current attributes, setting the current attributes, enabling attributes,
404 and disabling attributes.
405
406 @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance.
407 @param[in] Operation The operation to perform on the attributes for this
408 PCI controller.
409 @param[in] Attributes The mask of attributes that are used for Set,
410 Enable and Disable operations.
411 @param[out] Result A pointer to the result mask of attributes that are
412 returned for the Get and Supported operations. This
413 is an optional parameter that may be NULL for the
414 Set, Enable, and Disable operations.
415
416 @retval EFI_SUCCESS The operation on the PCI controller's
417 attributes was completed. If the operation
418 was Get or Supported, then the attribute mask
419 is returned in Result.
420 @retval EFI_INVALID_PARAMETER Operation is greater than or equal to
421 EfiPciIoAttributeOperationMaximum.
422 @retval EFI_INVALID_PARAMETER Operation is Get and Result is NULL.
423 @retval EFI_INVALID_PARAMETER Operation is Supported and Result is NULL.
424
425 **/
426 EFI_STATUS
427 PciIoAttributes (
428 IN EFI_PCI_IO_PROTOCOL *This,
429 IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation,
430 IN UINT64 Attributes,
431 OUT UINT64 *Result OPTIONAL
432 )
433 {
434 switch (Operation) {
435 case EfiPciIoAttributeOperationGet:
436 case EfiPciIoAttributeOperationSupported:
437 if (Result == NULL) {
438 return EFI_INVALID_PARAMETER;
439 }
440 //
441 // We are not a real PCI device so just say things we kind of do
442 //
443 *Result = EFI_PCI_DEVICE_ENABLE;
444 break;
445
446 case EfiPciIoAttributeOperationSet:
447 case EfiPciIoAttributeOperationEnable:
448 case EfiPciIoAttributeOperationDisable:
449 if (Attributes & (~EFI_PCI_DEVICE_ENABLE)) {
450 return EFI_UNSUPPORTED;
451 }
452 // Since we are not a real PCI device no enable/set or disable operations exist.
453 return EFI_SUCCESS;
454
455 default:
456 return EFI_INVALID_PARAMETER;
457 };
458 return EFI_SUCCESS;
459 }
460
461 EFI_STATUS
462 PciIoGetBarAttributes (
463 IN EFI_PCI_IO_PROTOCOL *This,
464 IN UINT8 BarIndex,
465 OUT UINT64 *Supports, OPTIONAL
466 OUT VOID **Resources OPTIONAL
467 )
468 {
469 ASSERT (FALSE);
470 return EFI_UNSUPPORTED;
471 }
472
473 EFI_STATUS
474 PciIoSetBarAttributes (
475 IN EFI_PCI_IO_PROTOCOL *This,
476 IN UINT64 Attributes,
477 IN UINT8 BarIndex,
478 IN OUT UINT64 *Offset,
479 IN OUT UINT64 *Length
480 )
481 {
482 ASSERT (FALSE);
483 return EFI_UNSUPPORTED;
484 }
485
486 EFI_PCI_IO_PROTOCOL PciIoTemplate =
487 {
488 PciIoPollMem,
489 PciIoPollIo,
490 { PciIoMemRead, PciIoMemWrite },
491 { PciIoIoRead, PciIoIoWrite },
492 { PciIoPciRead, PciIoPciWrite },
493 PciIoCopyMem,
494 PciIoMap,
495 PciIoUnmap,
496 PciIoAllocateBuffer,
497 PciIoFreeBuffer,
498 PciIoFlush,
499 PciIoGetLocation,
500 PciIoAttributes,
501 PciIoGetBarAttributes,
502 PciIoSetBarAttributes,
503 0,
504 0
505 };
506
507 EFI_STATUS
508 PciInstallDevice (
509 IN UINTN DeviceId,
510 IN PHYSICAL_ADDRESS MemoryStart,
511 IN UINT64 MemorySize,
512 IN UINTN ClassCode1,
513 IN UINTN ClassCode2,
514 IN UINTN ClassCode3
515 )
516 {
517 EFI_STATUS Status;
518 EFI_HANDLE Handle;
519 EFI_PCI_IO_PRIVATE_DATA *Private;
520
521 // Configure USB host
522 ConfigureUSBHost ();
523
524 // Create a private structure
525 Private = AllocatePool (sizeof (EFI_PCI_IO_PRIVATE_DATA));
526 if (Private == NULL) {
527 Status = EFI_OUT_OF_RESOURCES;
528 return Status;
529 }
530
531 Private->Signature = EFI_PCI_IO_PRIVATE_DATA_SIGNATURE; // Fill in signature
532 Private->RootBridge.Signature = PCI_ROOT_BRIDGE_SIGNATURE; // Fake Root Bridge structure needs a signature too
533 Private->RootBridge.MemoryStart = MemoryStart; // Get the USB capability register base
534 Private->Segment = 0; // Default to segment zero
535
536 // Calculate the total size of the USB controller (OHCI + EHCI).
537 Private->RootBridge.MemorySize = MemorySize; //CapabilityLength + (HOST_CONTROLLER_OPERATION_REG_SIZE + ((4 * PhysicalPorts) - 1));
538
539 // Create fake PCI config space: OHCI + EHCI
540 Private->ConfigSpace = AllocateZeroPool (sizeof (PCI_TYPE00));
541 if (Private->ConfigSpace == NULL) {
542 Status = EFI_OUT_OF_RESOURCES;
543 FreePool (Private);
544 return Status;
545 }
546
547 //
548 // Configure PCI config space: OHCI + EHCI
549 //
550 Private->ConfigSpace->Hdr.VendorId = 0x3530; //TODO: Define one
551 Private->ConfigSpace->Hdr.DeviceId = 0x3530; //TODO: Define one
552 Private->ConfigSpace->Hdr.ClassCode[0] = ClassCode1;
553 Private->ConfigSpace->Hdr.ClassCode[1] = ClassCode2;
554 Private->ConfigSpace->Hdr.ClassCode[2] = ClassCode3;
555 Private->ConfigSpace->Device.Bar[0] = MemoryStart;
556
557 Handle = NULL;
558
559 // Unique device path.
560 CopyMem (&Private->DevicePath, &PciIoDevicePathTemplate, sizeof (PciIoDevicePathTemplate));
561 Private->DevicePath.AcpiDevicePath.UID = 0;
562 Private->DevicePath.PciDevicePath.Device = DeviceId;
563
564 // Copy protocol structure
565 CopyMem (&Private->PciIoProtocol, &PciIoTemplate, sizeof (PciIoTemplate));
566
567 Status = gBS->InstallMultipleProtocolInterfaces (&Handle,
568 &gEfiPciIoProtocolGuid, &Private->PciIoProtocol,
569 &gEfiDevicePathProtocolGuid, &Private->DevicePath,
570 NULL);
571 if (EFI_ERROR (Status)) {
572 DEBUG ((EFI_D_ERROR, "PciEmulationEntryPoint InstallMultipleProtocolInterfaces () failed.\n"));
573 }
574
575 return Status;
576 }
577
578 EFI_STATUS
579 PciEmulationEntryPoint (
580 VOID
581 )
582 {
583 EFI_STATUS Status;
584
585 Status = PciInstallDevice (0, FixedPcdGet32 (PcdSynopsysUsbOhciBaseAddress), SIZE_64KB, PCI_IF_OHCI, PCI_CLASS_SERIAL_USB, PCI_CLASS_SERIAL);
586 if (EFI_ERROR (Status)) {
587 DEBUG ((EFI_D_ERROR, "PciEmulation: failed to install OHCI device.\n"));
588 }
589
590 Status = PciInstallDevice (1, FixedPcdGet32 (PcdSynopsysUsbEhciBaseAddress), SIZE_64KB, PCI_IF_EHCI, PCI_CLASS_SERIAL_USB, PCI_CLASS_SERIAL);
591 if (EFI_ERROR (Status)) {
592 DEBUG ((EFI_D_ERROR, "PciEmulation: failed to install EHCI device.\n"));
593 }
594
595 return Status;
596 }