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