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