]> git.proxmox.com Git - mirror_edk2.git/blob - BeagleBoardPkg/PciEmulation/PciEmulation.c
fa44570b4c0453f702e4052c9ba0588b8e159533
[mirror_edk2.git] / BeagleBoardPkg / PciEmulation / PciEmulation.c
1 /** @file
2
3 Copyright (c) 2008-2009, Apple Inc. All rights reserved.
4
5 All rights reserved. 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 #include "PciEmulation.h"
16 #include <Omap3530/Omap3530.h>
17
18 EFI_CPU_ARCH_PROTOCOL *gCpu;
19 EMBEDDED_EXTERNAL_DEVICE *gTPS65950;
20
21 #define HOST_CONTROLLER_OPERATION_REG_SIZE 0x44
22
23 typedef struct {
24 ACPI_HID_DEVICE_PATH AcpiDevicePath;
25 PCI_DEVICE_PATH PciDevicePath;
26 EFI_DEVICE_PATH_PROTOCOL EndDevicePath;
27 } EFI_PCI_IO_DEVICE_PATH;
28
29 typedef struct {
30 UINT32 Signature;
31 EFI_PCI_IO_DEVICE_PATH DevicePath;
32 EFI_PCI_IO_PROTOCOL PciIoProtocol;
33 PCI_TYPE00 *ConfigSpace;
34 PCI_ROOT_BRIDGE RootBridge;
35 UINTN Segment;
36 } EFI_PCI_IO_PRIVATE_DATA;
37
38 #define EFI_PCI_IO_PRIVATE_DATA_SIGNATURE SIGNATURE_32('p', 'c', 'i', 'o')
39 #define EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(a) CR(a, EFI_PCI_IO_PRIVATE_DATA, PciIoProtocol, EFI_PCI_IO_PRIVATE_DATA_SIGNATURE)
40
41 EFI_PCI_IO_DEVICE_PATH PciIoDevicePathTemplate =
42 {
43 {
44 { ACPI_DEVICE_PATH, ACPI_DP, sizeof (ACPI_HID_DEVICE_PATH), 0},
45 EISA_PNP_ID(0x0A03), // HID
46 0 // UID
47 },
48 {
49 { HARDWARE_DEVICE_PATH, HW_PCI_DP, sizeof (PCI_DEVICE_PATH), 0},
50 0,
51 0
52 },
53 { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, sizeof (EFI_DEVICE_PATH_PROTOCOL), 0}
54 };
55
56 STATIC
57 VOID
58 ConfigureUSBHost (
59 VOID
60 )
61 {
62 EFI_STATUS Status;
63 UINT8 Data = 0;
64
65 // Take USB host out of force-standby mode
66 MmioWrite32(UHH_SYSCONFIG, UHH_SYSCONFIG_MIDLEMODE_NO_STANDBY
67 | UHH_SYSCONFIG_CLOCKACTIVITY_ON
68 | UHH_SYSCONFIG_SIDLEMODE_NO_STANDBY
69 | UHH_SYSCONFIG_ENAWAKEUP_ENABLE
70 | UHH_SYSCONFIG_AUTOIDLE_ALWAYS_RUN);
71 MmioWrite32(UHH_HOSTCONFIG, UHH_HOSTCONFIG_P3_CONNECT_STATUS_DISCONNECT
72 | UHH_HOSTCONFIG_P2_CONNECT_STATUS_DISCONNECT
73 | UHH_HOSTCONFIG_P1_CONNECT_STATUS_DISCONNECT
74 | UHH_HOSTCONFIG_ENA_INCR_ALIGN_DISABLE
75 | UHH_HOSTCONFIG_ENA_INCR16_ENABLE
76 | UHH_HOSTCONFIG_ENA_INCR8_ENABLE
77 | UHH_HOSTCONFIG_ENA_INCR4_ENABLE
78 | UHH_HOSTCONFIG_AUTOPPD_ON_OVERCUR_EN_ON
79 | UHH_HOSTCONFIG_P1_ULPI_BYPASS_ULPI_MODE);
80
81 // USB reset (GPIO 147 - Port 5 pin 19) output high
82 MmioAnd32(GPIO5_BASE + GPIO_OE, ~BIT19);
83 MmioWrite32(GPIO5_BASE + GPIO_SETDATAOUT, BIT19);
84
85 // Get the Power IC protocol.
86 Status = gBS->LocateProtocol(&gEmbeddedExternalDeviceProtocolGuid, NULL, (VOID **)&gTPS65950);
87 ASSERT_EFI_ERROR(Status);
88
89 //Enable power to the USB host.
90 Status = gTPS65950->Read(gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID3, LEDEN), 1, &Data);
91 ASSERT_EFI_ERROR(Status);
92
93 //LEDAON & LEDAPWM control the power to the USB host so enable those bits.
94 Data |= (LEDAON | LEDAPWM);
95
96 Status = gTPS65950->Write(gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID3, LEDEN), 1, &Data);
97 ASSERT_EFI_ERROR(Status);
98 }
99
100 EFI_STATUS
101 PciIoPollMem (
102 IN EFI_PCI_IO_PROTOCOL *This,
103 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
104 IN UINT8 BarIndex,
105 IN UINT64 Offset,
106 IN UINT64 Mask,
107 IN UINT64 Value,
108 IN UINT64 Delay,
109 OUT UINT64 *Result
110 )
111 {
112 ASSERT (FALSE);
113 return EFI_UNSUPPORTED;
114 }
115
116 EFI_STATUS
117 PciIoPollIo (
118 IN EFI_PCI_IO_PROTOCOL *This,
119 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
120 IN UINT8 BarIndex,
121 IN UINT64 Offset,
122 IN UINT64 Mask,
123 IN UINT64 Value,
124 IN UINT64 Delay,
125 OUT UINT64 *Result
126 )
127 {
128 ASSERT (FALSE);
129 return EFI_UNSUPPORTED;
130 }
131
132 EFI_STATUS
133 PciIoMemRead (
134 IN EFI_PCI_IO_PROTOCOL *This,
135 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
136 IN UINT8 BarIndex,
137 IN UINT64 Offset,
138 IN UINTN Count,
139 IN OUT VOID *Buffer
140 )
141 {
142 EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This);
143
144 return PciRootBridgeIoMemRead (&Private->RootBridge.Io,
145 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
146 Private->ConfigSpace->Device.Bar[BarIndex] + Offset,
147 Count,
148 Buffer
149 );
150 }
151
152 EFI_STATUS
153 PciIoMemWrite (
154 IN EFI_PCI_IO_PROTOCOL *This,
155 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
156 IN UINT8 BarIndex,
157 IN UINT64 Offset,
158 IN UINTN Count,
159 IN OUT VOID *Buffer
160 )
161 {
162 EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This);
163
164 return PciRootBridgeIoMemWrite (&Private->RootBridge.Io,
165 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
166 Private->ConfigSpace->Device.Bar[BarIndex] + Offset,
167 Count,
168 Buffer
169 );
170 }
171
172 EFI_STATUS
173 PciIoIoRead (
174 IN EFI_PCI_IO_PROTOCOL *This,
175 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
176 IN UINT8 BarIndex,
177 IN UINT64 Offset,
178 IN UINTN Count,
179 IN OUT VOID *Buffer
180 )
181 {
182 ASSERT (FALSE);
183 return EFI_UNSUPPORTED;
184 }
185
186 EFI_STATUS
187 PciIoIoWrite (
188 IN EFI_PCI_IO_PROTOCOL *This,
189 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
190 IN UINT8 BarIndex,
191 IN UINT64 Offset,
192 IN UINTN Count,
193 IN OUT VOID *Buffer
194 )
195 {
196 ASSERT (FALSE);
197 return EFI_UNSUPPORTED;
198 }
199
200 EFI_STATUS
201 PciIoPciRead (
202 IN EFI_PCI_IO_PROTOCOL *This,
203 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
204 IN UINT32 Offset,
205 IN UINTN Count,
206 IN OUT VOID *Buffer
207 )
208 {
209 EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This);
210
211 return PciRootBridgeIoMemRW ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)Width,
212 Count,
213 TRUE,
214 (PTR)(UINTN)Buffer,
215 TRUE,
216 (PTR)(UINTN)(((UINT8 *)Private->ConfigSpace) + Offset)
217 );
218 }
219
220 EFI_STATUS
221 PciIoPciWrite (
222 IN EFI_PCI_IO_PROTOCOL *This,
223 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
224 IN UINT32 Offset,
225 IN UINTN Count,
226 IN OUT VOID *Buffer
227 )
228 {
229 EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This);
230
231 return PciRootBridgeIoMemRW ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
232 Count,
233 TRUE,
234 (PTR)(UINTN)(((UINT8 *)Private->ConfigSpace) + Offset),
235 TRUE,
236 (PTR)(UINTN)Buffer
237 );
238 }
239
240 EFI_STATUS
241 PciIoCopyMem (
242 IN EFI_PCI_IO_PROTOCOL *This,
243 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
244 IN UINT8 DestBarIndex,
245 IN UINT64 DestOffset,
246 IN UINT8 SrcBarIndex,
247 IN UINT64 SrcOffset,
248 IN UINTN Count
249 )
250 {
251 ASSERT (FALSE);
252 return EFI_UNSUPPORTED;
253 }
254
255 EFI_STATUS
256 PciIoMap (
257 IN EFI_PCI_IO_PROTOCOL *This,
258 IN EFI_PCI_IO_PROTOCOL_OPERATION Operation,
259 IN VOID *HostAddress,
260 IN OUT UINTN *NumberOfBytes,
261 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
262 OUT VOID **Mapping
263 )
264 {
265 MAP_INFO_INSTANCE *Map;
266 EFI_STATUS Status;
267
268 if ( HostAddress == NULL || NumberOfBytes == NULL ||
269 DeviceAddress == NULL || Mapping == NULL ) {
270
271 return EFI_INVALID_PARAMETER;
272 }
273
274
275 if (Operation >= EfiPciOperationMaximum) {
276 return EFI_INVALID_PARAMETER;
277 }
278
279 *DeviceAddress = ConvertToPhysicalAddress (HostAddress);
280
281 // Data cache flush (HostAddress, NumberOfBytes);
282
283 // Remember range so we can flush on the other side
284 Status = gBS->AllocatePool (EfiBootServicesData, sizeof (PCI_DMA_MAP), (VOID **) &Map);
285 if (EFI_ERROR(Status)) {
286 return EFI_OUT_OF_RESOURCES;
287 }
288
289 *Mapping = Map;
290
291 Map->HostAddress = (UINTN)HostAddress;
292 Map->DeviceAddress = *DeviceAddress;
293 Map->NumberOfBytes = *NumberOfBytes;
294 Map->Operation = Operation;
295
296 // EfiCpuFlushTypeWriteBack, EfiCpuFlushTypeInvalidate
297 gCpu->FlushDataCache (gCpu, (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress, *NumberOfBytes, EfiCpuFlushTypeWriteBackInvalidate);
298
299 return EFI_SUCCESS;
300 }
301
302 EFI_STATUS
303 PciIoUnmap (
304 IN EFI_PCI_IO_PROTOCOL *This,
305 IN VOID *Mapping
306 )
307 {
308 PCI_DMA_MAP *Map;
309
310 if (Mapping == NULL) {
311 ASSERT (FALSE);
312 return EFI_INVALID_PARAMETER;
313 }
314
315 Map = (PCI_DMA_MAP *)Mapping;
316 if (Map->Operation == EfiPciOperationBusMasterWrite) {
317 //
318 // Make sure we read buffer from uncached memory and not the cache
319 //
320 gCpu->FlushDataCache (gCpu, Map->HostAddress, Map->NumberOfBytes, EfiCpuFlushTypeInvalidate);
321 }
322
323 FreePool (Map);
324
325 return EFI_SUCCESS;
326 }
327
328 EFI_STATUS
329 PciIoAllocateBuffer (
330 IN EFI_PCI_IO_PROTOCOL *This,
331 IN EFI_ALLOCATE_TYPE Type,
332 IN EFI_MEMORY_TYPE MemoryType,
333 IN UINTN Pages,
334 OUT VOID **HostAddress,
335 IN UINT64 Attributes
336 )
337 {
338 if (Attributes & EFI_PCI_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER) {
339 return EFI_UNSUPPORTED;
340 }
341
342 if (HostAddress == NULL) {
343 return EFI_INVALID_PARAMETER;
344 }
345
346 //
347 // The only valid memory types are EfiBootServicesData and EfiRuntimeServicesData
348 //
349 // We used uncached memory to keep coherency
350 //
351 if (MemoryType == EfiBootServicesData) {
352 *HostAddress = UncachedAllocatePages (Pages);
353 } else if (MemoryType != EfiRuntimeServicesData) {
354 *HostAddress = UncachedAllocateRuntimePages (Pages);
355 } else {
356 return EFI_INVALID_PARAMETER;
357 }
358
359 return EFI_SUCCESS;
360 }
361
362 EFI_STATUS
363 PciIoFreeBuffer (
364 IN EFI_PCI_IO_PROTOCOL *This,
365 IN UINTN Pages,
366 IN VOID *HostAddress
367 )
368 {
369 if (HostAddress == NULL) {
370 return EFI_INVALID_PARAMETER;
371 }
372
373 UncachedFreePages (HostAddress, Pages);
374 return EFI_SUCCESS;
375 }
376
377
378 EFI_STATUS
379 PciIoFlush (
380 IN EFI_PCI_IO_PROTOCOL *This
381 )
382 {
383 return EFI_SUCCESS;
384 }
385
386 EFI_STATUS
387 PciIoGetLocation (
388 IN EFI_PCI_IO_PROTOCOL *This,
389 OUT UINTN *SegmentNumber,
390 OUT UINTN *BusNumber,
391 OUT UINTN *DeviceNumber,
392 OUT UINTN *FunctionNumber
393 )
394 {
395 EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This);
396
397 if (SegmentNumber != NULL) {
398 *SegmentNumber = Private->Segment;
399 }
400
401 if (BusNumber != NULL) {
402 *BusNumber = 0xff;
403 }
404
405 if (DeviceNumber != NULL) {
406 *DeviceNumber = 0;
407 }
408
409 if (FunctionNumber != NULL) {
410 *FunctionNumber = 0;
411 }
412
413 return EFI_SUCCESS;
414 }
415
416 EFI_STATUS
417 PciIoAttributes (
418 IN EFI_PCI_IO_PROTOCOL *This,
419 IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation,
420 IN UINT64 Attributes,
421 OUT UINT64 *Result OPTIONAL
422 )
423 {
424 switch (Operation) {
425 case EfiPciIoAttributeOperationGet:
426 case EfiPciIoAttributeOperationSupported:
427 if (Result == NULL) {
428 return EFI_INVALID_PARAMETER;
429 }
430 // We are not a real PCI device so just say things we kind of do
431 *Result = EFI_PCI_IO_ATTRIBUTE_MEMORY | EFI_PCI_IO_ATTRIBUTE_BUS_MASTER | EFI_PCI_DEVICE_ENABLE;
432 break;
433
434 case EfiPciIoAttributeOperationSet:
435 case EfiPciIoAttributeOperationEnable:
436 case EfiPciIoAttributeOperationDisable:
437 // Since we are not a real PCI device no enable/set or disable operations exist.
438 return EFI_SUCCESS;
439
440 default:
441 ASSERT (FALSE);
442 return EFI_INVALID_PARAMETER;
443 };
444 return EFI_SUCCESS;
445 }
446
447 EFI_STATUS
448 PciIoGetBarAttributes (
449 IN EFI_PCI_IO_PROTOCOL *This,
450 IN UINT8 BarIndex,
451 OUT UINT64 *Supports, OPTIONAL
452 OUT VOID **Resources OPTIONAL
453 )
454 {
455 ASSERT (FALSE);
456 return EFI_UNSUPPORTED;
457 }
458
459 EFI_STATUS
460 PciIoSetBarAttributes (
461 IN EFI_PCI_IO_PROTOCOL *This,
462 IN UINT64 Attributes,
463 IN UINT8 BarIndex,
464 IN OUT UINT64 *Offset,
465 IN OUT UINT64 *Length
466 )
467 {
468 ASSERT (FALSE);
469 return EFI_UNSUPPORTED;
470 }
471
472 EFI_PCI_IO_PROTOCOL PciIoTemplate =
473 {
474 PciIoPollMem,
475 PciIoPollIo,
476 PciIoMemRead,
477 PciIoMemWrite,
478 PciIoIoRead,
479 PciIoIoWrite,
480 PciIoPciRead,
481 PciIoPciWrite,
482 PciIoCopyMem,
483 PciIoMap,
484 PciIoUnmap,
485 PciIoAllocateBuffer,
486 PciIoFreeBuffer,
487 PciIoFlush,
488 PciIoGetLocation,
489 PciIoAttributes,
490 PciIoGetBarAttributes,
491 PciIoSetBarAttributes,
492 0,
493 0
494 };
495
496 EFI_STATUS
497 EFIAPI
498 PciEmulationEntryPoint (
499 IN EFI_HANDLE ImageHandle,
500 IN EFI_SYSTEM_TABLE *SystemTable
501 )
502 {
503 EFI_STATUS Status;
504 EFI_HANDLE Handle;
505 EFI_PCI_IO_PRIVATE_DATA *Private;
506 UINT8 CapabilityLength;
507 UINT8 PhysicalPorts;
508 UINTN Count;
509
510 // Get the Cpu protocol for later use
511 Status = gBS->LocateProtocol(&gEfiCpuArchProtocolGuid, NULL, (VOID **)&gCpu);
512 ASSERT_EFI_ERROR(Status);
513
514 //Configure USB host for OMAP3530.
515 ConfigureUSBHost();
516
517 // Create a private structure
518 Private = AllocatePool(sizeof(EFI_PCI_IO_PRIVATE_DATA));
519 if (Private == NULL) {
520 Status = EFI_OUT_OF_RESOURCES;
521 return Status;
522 }
523
524 Private->Signature = EFI_PCI_IO_PRIVATE_DATA_SIGNATURE; // Fill in signature
525 Private->RootBridge.Signature = PCI_ROOT_BRIDGE_SIGNATURE; // Fake Root Bridge structure needs a signature too
526 Private->RootBridge.MemoryStart = USB_EHCI_HCCAPBASE; // Get the USB capability register base
527 Private->Segment = 0; // Default to segment zero
528
529 // Find out the capability register length and number of physical ports.
530 CapabilityLength = MmioRead8(Private->RootBridge.MemoryStart);
531 PhysicalPorts = (MmioRead32(Private->RootBridge.MemoryStart + 0x4)) & 0x0000000F;
532
533 // Calculate the total size of the USB registers.
534 Private->RootBridge.MemorySize = CapabilityLength + (HOST_CONTROLLER_OPERATION_REG_SIZE + ((4 * PhysicalPorts) - 1));
535
536 // Enable Port Power bit in Port status and control registers in EHCI register space.
537 // Port Power Control (PPC) bit in the HCSPARAMS register is already set which indicates
538 // host controller implementation includes port power control.
539 for (Count = 0; Count < PhysicalPorts; Count++) {
540 MmioOr32((Private->RootBridge.MemoryStart + CapabilityLength + HOST_CONTROLLER_OPERATION_REG_SIZE + 4*Count), 0x00001000);
541 }
542
543 // Create fake PCI config space.
544 Private->ConfigSpace = AllocateZeroPool(sizeof(PCI_TYPE00));
545 if (Private->ConfigSpace == NULL) {
546 Status = EFI_OUT_OF_RESOURCES;
547 FreePool(Private);
548 return Status;
549 }
550
551 // Configure PCI config space
552 Private->ConfigSpace->Hdr.VendorId = 0x3530;
553 Private->ConfigSpace->Hdr.DeviceId = 0x3530;
554 Private->ConfigSpace->Hdr.ClassCode[0] = 0x20;
555 Private->ConfigSpace->Hdr.ClassCode[1] = 0x03;
556 Private->ConfigSpace->Hdr.ClassCode[2] = 0x0C;
557 Private->ConfigSpace->Device.Bar[0] = Private->RootBridge.MemoryStart;
558
559 Handle = NULL;
560
561 // Unique device path.
562 CopyMem(&Private->DevicePath, &PciIoDevicePathTemplate, sizeof(PciIoDevicePathTemplate));
563 Private->DevicePath.AcpiDevicePath.UID = 0;
564
565 // Copy protocol structure
566 CopyMem(&Private->PciIoProtocol, &PciIoTemplate, sizeof(PciIoTemplate));
567
568 Status = gBS->InstallMultipleProtocolInterfaces(&Handle,
569 &gEfiPciIoProtocolGuid, &Private->PciIoProtocol,
570 &gEfiDevicePathProtocolGuid, &Private->DevicePath,
571 NULL);
572 if (EFI_ERROR(Status)) {
573 DEBUG((EFI_D_ERROR, "PciEmulationEntryPoint InstallMultipleProtocolInterfaces() failed.\n"));
574 }
575
576 return Status;
577 }
578