dee054197163650a3f3cebae8e545503666ef982
[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 } else if (Map->Operation == EfiPciOperationBusMasterCommonBuffer) {
322 //
323 // CPU was using uncached address, so anything in the cached range is bogus
324 //
325 gCpu->FlushDataCache (gCpu, Map->DeviceAddress, Map->NumberOfBytes, EfiCpuFlushTypeInvalidate);
326 }
327
328 FreePool (Map);
329
330 return EFI_SUCCESS;
331 }
332
333 EFI_STATUS
334 PciIoAllocateBuffer (
335 IN EFI_PCI_IO_PROTOCOL *This,
336 IN EFI_ALLOCATE_TYPE Type,
337 IN EFI_MEMORY_TYPE MemoryType,
338 IN UINTN Pages,
339 OUT VOID **HostAddress,
340 IN UINT64 Attributes
341 )
342 {
343 if (Attributes & EFI_PCI_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER) {
344 return EFI_UNSUPPORTED;
345 }
346
347 if (HostAddress == NULL) {
348 return EFI_INVALID_PARAMETER;
349 }
350
351 //
352 // The only valid memory types are EfiBootServicesData and EfiRuntimeServicesData
353 //
354 // We used uncached memory to keep coherency
355 //
356 if (MemoryType == EfiBootServicesData) {
357 *HostAddress = UncachedAllocatePages (Pages);
358 } else if (MemoryType != EfiRuntimeServicesData) {
359 *HostAddress = UncachedAllocateRuntimePages (Pages);
360 } else {
361 return EFI_INVALID_PARAMETER;
362 }
363
364 return EFI_SUCCESS;
365 }
366
367 EFI_STATUS
368 PciIoFreeBuffer (
369 IN EFI_PCI_IO_PROTOCOL *This,
370 IN UINTN Pages,
371 IN VOID *HostAddress
372 )
373 {
374 if (HostAddress == NULL) {
375 return EFI_INVALID_PARAMETER;
376 }
377
378 UncachedFreePages (HostAddress, Pages);
379 return EFI_SUCCESS;
380 }
381
382
383 EFI_STATUS
384 PciIoFlush (
385 IN EFI_PCI_IO_PROTOCOL *This
386 )
387 {
388 return EFI_SUCCESS;
389 }
390
391 EFI_STATUS
392 PciIoGetLocation (
393 IN EFI_PCI_IO_PROTOCOL *This,
394 OUT UINTN *SegmentNumber,
395 OUT UINTN *BusNumber,
396 OUT UINTN *DeviceNumber,
397 OUT UINTN *FunctionNumber
398 )
399 {
400 EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This);
401
402 if (SegmentNumber != NULL) {
403 *SegmentNumber = Private->Segment;
404 }
405
406 if (BusNumber != NULL) {
407 *BusNumber = 0xff;
408 }
409
410 if (DeviceNumber != NULL) {
411 *DeviceNumber = 0;
412 }
413
414 if (FunctionNumber != NULL) {
415 *FunctionNumber = 0;
416 }
417
418 return EFI_SUCCESS;
419 }
420
421 EFI_STATUS
422 PciIoAttributes (
423 IN EFI_PCI_IO_PROTOCOL *This,
424 IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation,
425 IN UINT64 Attributes,
426 OUT UINT64 *Result OPTIONAL
427 )
428 {
429 switch (Operation) {
430 case EfiPciIoAttributeOperationGet:
431 case EfiPciIoAttributeOperationSupported:
432 if (Result == NULL) {
433 return EFI_INVALID_PARAMETER;
434 }
435 // We are not a real PCI device so just say things we kind of do
436 *Result = EFI_PCI_IO_ATTRIBUTE_MEMORY | EFI_PCI_IO_ATTRIBUTE_BUS_MASTER | EFI_PCI_DEVICE_ENABLE;
437 break;
438
439 case EfiPciIoAttributeOperationSet:
440 case EfiPciIoAttributeOperationEnable:
441 case EfiPciIoAttributeOperationDisable:
442 // Since we are not a real PCI device no enable/set or disable operations exist.
443 return EFI_SUCCESS;
444 break;
445
446 default:
447 ASSERT (FALSE);
448 return EFI_INVALID_PARAMETER;
449 };
450 return EFI_SUCCESS;
451 }
452
453 EFI_STATUS
454 PciIoGetBarAttributes (
455 IN EFI_PCI_IO_PROTOCOL *This,
456 IN UINT8 BarIndex,
457 OUT UINT64 *Supports, OPTIONAL
458 OUT VOID **Resources OPTIONAL
459 )
460 {
461 ASSERT (FALSE);
462 return EFI_UNSUPPORTED;
463 }
464
465 EFI_STATUS
466 PciIoSetBarAttributes (
467 IN EFI_PCI_IO_PROTOCOL *This,
468 IN UINT64 Attributes,
469 IN UINT8 BarIndex,
470 IN OUT UINT64 *Offset,
471 IN OUT UINT64 *Length
472 )
473 {
474 ASSERT (FALSE);
475 return EFI_UNSUPPORTED;
476 }
477
478 EFI_PCI_IO_PROTOCOL PciIoTemplate =
479 {
480 PciIoPollMem,
481 PciIoPollIo,
482 PciIoMemRead,
483 PciIoMemWrite,
484 PciIoIoRead,
485 PciIoIoWrite,
486 PciIoPciRead,
487 PciIoPciWrite,
488 PciIoCopyMem,
489 PciIoMap,
490 PciIoUnmap,
491 PciIoAllocateBuffer,
492 PciIoFreeBuffer,
493 PciIoFlush,
494 PciIoGetLocation,
495 PciIoAttributes,
496 PciIoGetBarAttributes,
497 PciIoSetBarAttributes,
498 0,
499 0
500 };
501
502 EFI_STATUS
503 EFIAPI
504 PciEmulationEntryPoint (
505 IN EFI_HANDLE ImageHandle,
506 IN EFI_SYSTEM_TABLE *SystemTable
507 )
508 {
509 EFI_STATUS Status;
510 EFI_HANDLE Handle;
511 EFI_PCI_IO_PRIVATE_DATA *Private;
512 UINT8 CapabilityLength;
513 UINT8 PhysicalPorts;
514 UINTN Count;
515
516 // Get the Cpu protocol for later use
517 Status = gBS->LocateProtocol(&gEfiCpuArchProtocolGuid, NULL, (VOID **)&gCpu);
518 ASSERT_EFI_ERROR(Status);
519
520 //Configure USB host for OMAP3530.
521 ConfigureUSBHost();
522
523 // Create a private structure
524 Private = AllocatePool(sizeof(EFI_PCI_IO_PRIVATE_DATA));
525 if (Private == NULL) {
526 Status = EFI_OUT_OF_RESOURCES;
527 return Status;
528 }
529
530 Private->Signature = EFI_PCI_IO_PRIVATE_DATA_SIGNATURE; // Fill in signature
531 Private->RootBridge.Signature = PCI_ROOT_BRIDGE_SIGNATURE; // Fake Root Bridge structure needs a signature too
532 Private->RootBridge.MemoryStart = USB_EHCI_HCCAPBASE; // Get the USB capability register base
533 Private->Segment = 0; // Default to segment zero
534
535 // Find out the capability register length and number of physical ports.
536 CapabilityLength = MmioRead8(Private->RootBridge.MemoryStart);
537 PhysicalPorts = (MmioRead32(Private->RootBridge.MemoryStart + 0x4)) & 0x0000000F;
538
539 // Calculate the total size of the USB registers.
540 Private->RootBridge.MemorySize = CapabilityLength + (HOST_CONTROLLER_OPERATION_REG_SIZE + ((4 * PhysicalPorts) - 1));
541
542 // Enable Port Power bit in Port status and control registers in EHCI register space.
543 // Port Power Control (PPC) bit in the HCSPARAMS register is already set which indicates
544 // host controller implementation includes port power control.
545 for (Count = 0; Count < PhysicalPorts; Count++) {
546 MmioOr32((Private->RootBridge.MemoryStart + CapabilityLength + HOST_CONTROLLER_OPERATION_REG_SIZE + 4*Count), 0x00001000);
547 }
548
549 // Create fake PCI config space.
550 Private->ConfigSpace = AllocateZeroPool(sizeof(PCI_TYPE00));
551 if (Private->ConfigSpace == NULL) {
552 Status = EFI_OUT_OF_RESOURCES;
553 FreePool(Private);
554 return Status;
555 }
556
557 // Configure PCI config space
558 Private->ConfigSpace->Hdr.VendorId = 0x3530;
559 Private->ConfigSpace->Hdr.DeviceId = 0x3530;
560 Private->ConfigSpace->Hdr.ClassCode[0] = 0x20;
561 Private->ConfigSpace->Hdr.ClassCode[1] = 0x03;
562 Private->ConfigSpace->Hdr.ClassCode[2] = 0x0C;
563 Private->ConfigSpace->Device.Bar[0] = Private->RootBridge.MemoryStart;
564
565 Handle = NULL;
566
567 // Unique device path.
568 CopyMem(&Private->DevicePath, &PciIoDevicePathTemplate, sizeof(PciIoDevicePathTemplate));
569 Private->DevicePath.AcpiDevicePath.UID = 0;
570
571 // Copy protocol structure
572 CopyMem(&Private->PciIoProtocol, &PciIoTemplate, sizeof(PciIoTemplate));
573
574 Status = gBS->InstallMultipleProtocolInterfaces(&Handle,
575 &gEfiPciIoProtocolGuid, &Private->PciIoProtocol,
576 &gEfiDevicePathProtocolGuid, &Private->DevicePath,
577 NULL);
578 if (EFI_ERROR(Status)) {
579 DEBUG((EFI_D_ERROR, "PciEmulationEntryPoint InstallMultipleProtocolInterfaces() failed.\n"));
580 }
581
582 return Status;
583 }
584