1 /** @file
2 PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid
3 which is used to enable recovery function from USB Drivers.
4 
5 Copyright (c) 2010 - 2013, Intel Corporation. All rights reserved.<BR>
6 
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions
9 of the BSD License which accompanies this distribution.  The
10 full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
12 
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 
16 **/
17 
18 #include "EhcPeim.h"
19 
20 //
21 // Two arrays used to translate the EHCI port state (change)
22 // to the UEFI protocol's port state (change).
23 //
24 USB_PORT_STATE_MAP  mUsbPortStateMap[] = {
25   {PORTSC_CONN,     USB_PORT_STAT_CONNECTION},
26   {PORTSC_ENABLED,  USB_PORT_STAT_ENABLE},
27   {PORTSC_SUSPEND,  USB_PORT_STAT_SUSPEND},
28   {PORTSC_OVERCUR,  USB_PORT_STAT_OVERCURRENT},
29   {PORTSC_RESET,    USB_PORT_STAT_RESET},
30   {PORTSC_POWER,    USB_PORT_STAT_POWER},
31   {PORTSC_OWNER,    USB_PORT_STAT_OWNER}
32 };
33 
34 USB_PORT_STATE_MAP  mUsbPortChangeMap[] = {
35   {PORTSC_CONN_CHANGE,    USB_PORT_STAT_C_CONNECTION},
36   {PORTSC_ENABLE_CHANGE,  USB_PORT_STAT_C_ENABLE},
37   {PORTSC_OVERCUR_CHANGE, USB_PORT_STAT_C_OVERCURRENT}
38 };
39 
40 /**
41   Read Ehc Operation register.
42 
43   @param  Ehc       The EHCI device.
44   @param  Offset    The operation register offset.
45 
46   @retval the register content read.
47 
48 **/
49 UINT32
EhcReadOpReg(IN PEI_USB2_HC_DEV * Ehc,IN UINT32 Offset)50 EhcReadOpReg (
51   IN  PEI_USB2_HC_DEV     *Ehc,
52   IN  UINT32              Offset
53   )
54 {
55   UINT32                  Data;
56 
57   ASSERT (Ehc->CapLen != 0);
58 
59   Data = MmioRead32 (Ehc->UsbHostControllerBaseAddress + Ehc->CapLen + Offset);
60 
61   return Data;
62 }
63 
64 /**
65   Write the data to the EHCI operation register.
66 
67   @param  Ehc       The EHCI device.
68   @param  Offset    EHCI operation register offset.
69   @param  Data      The data to write.
70 
71 **/
72 VOID
EhcWriteOpReg(IN PEI_USB2_HC_DEV * Ehc,IN UINT32 Offset,IN UINT32 Data)73 EhcWriteOpReg (
74   IN PEI_USB2_HC_DEV      *Ehc,
75   IN UINT32               Offset,
76   IN UINT32               Data
77   )
78 {
79 
80   ASSERT (Ehc->CapLen != 0);
81 
82   MmioWrite32(Ehc->UsbHostControllerBaseAddress + Ehc->CapLen + Offset, Data);
83 
84 }
85 
86 /**
87   Set one bit of the operational register while keeping other bits.
88 
89   @param  Ehc       The EHCI device.
90   @param  Offset    The offset of the operational register.
91   @param  Bit       The bit mask of the register to set.
92 
93 **/
94 VOID
EhcSetOpRegBit(IN PEI_USB2_HC_DEV * Ehc,IN UINT32 Offset,IN UINT32 Bit)95 EhcSetOpRegBit (
96   IN PEI_USB2_HC_DEV      *Ehc,
97   IN UINT32               Offset,
98   IN UINT32               Bit
99   )
100 {
101   UINT32                  Data;
102 
103   Data  = EhcReadOpReg (Ehc, Offset);
104   Data |= Bit;
105   EhcWriteOpReg (Ehc, Offset, Data);
106 }
107 
108 /**
109   Clear one bit of the operational register while keeping other bits.
110 
111   @param  Ehc       The EHCI device.
112   @param  Offset    The offset of the operational register.
113   @param  Bit       The bit mask of the register to clear.
114 
115 **/
116 VOID
EhcClearOpRegBit(IN PEI_USB2_HC_DEV * Ehc,IN UINT32 Offset,IN UINT32 Bit)117 EhcClearOpRegBit (
118   IN PEI_USB2_HC_DEV      *Ehc,
119   IN UINT32               Offset,
120   IN UINT32               Bit
121   )
122 {
123   UINT32                  Data;
124 
125   Data  = EhcReadOpReg (Ehc, Offset);
126   Data &= ~Bit;
127   EhcWriteOpReg (Ehc, Offset, Data);
128 }
129 
130 /**
131   Wait the operation register's bit as specified by Bit
132   to become set (or clear).
133 
134   @param  Ehc           The EHCI device.
135   @param  Offset        The offset of the operational register.
136   @param  Bit           The bit mask of the register to wait for.
137   @param  WaitToSet     Wait the bit to set or clear.
138   @param  Timeout       The time to wait before abort (in millisecond).
139 
140   @retval EFI_SUCCESS   The bit successfully changed by host controller.
141   @retval EFI_TIMEOUT   The time out occurred.
142 
143 **/
144 EFI_STATUS
EhcWaitOpRegBit(IN PEI_USB2_HC_DEV * Ehc,IN UINT32 Offset,IN UINT32 Bit,IN BOOLEAN WaitToSet,IN UINT32 Timeout)145 EhcWaitOpRegBit (
146   IN PEI_USB2_HC_DEV      *Ehc,
147   IN UINT32               Offset,
148   IN UINT32               Bit,
149   IN BOOLEAN              WaitToSet,
150   IN UINT32               Timeout
151   )
152 {
153   UINT32                  Index;
154 
155   for (Index = 0; Index < Timeout / EHC_SYNC_POLL_INTERVAL + 1; Index++) {
156     if (EHC_REG_BIT_IS_SET (Ehc, Offset, Bit) == WaitToSet) {
157       return EFI_SUCCESS;
158     }
159 
160     MicroSecondDelay (EHC_SYNC_POLL_INTERVAL);
161   }
162 
163   return EFI_TIMEOUT;
164 }
165 
166 /**
167   Read EHCI capability register.
168 
169   @param  Ehc       The EHCI device.
170   @param  Offset    Capability register address.
171 
172   @retval the register content read.
173 
174 **/
175 UINT32
EhcReadCapRegister(IN PEI_USB2_HC_DEV * Ehc,IN UINT32 Offset)176 EhcReadCapRegister (
177   IN  PEI_USB2_HC_DEV     *Ehc,
178   IN  UINT32              Offset
179   )
180 {
181   UINT32                  Data;
182 
183   Data = MmioRead32(Ehc->UsbHostControllerBaseAddress + Offset);
184 
185   return Data;
186 }
187 
188 /**
189   Set door bell and wait it to be ACKed by host controller.
190   This function is used to synchronize with the hardware.
191 
192   @param  Ehc       The EHCI device.
193   @param  Timeout   The time to wait before abort (in millisecond, ms).
194 
195   @retval EFI_TIMEOUT       Time out happened while waiting door bell to set.
196   @retval EFI_SUCCESS       Synchronized with the hardware.
197 
198 **/
199 EFI_STATUS
EhcSetAndWaitDoorBell(IN PEI_USB2_HC_DEV * Ehc,IN UINT32 Timeout)200 EhcSetAndWaitDoorBell (
201   IN  PEI_USB2_HC_DEV     *Ehc,
202   IN  UINT32              Timeout
203   )
204 {
205   EFI_STATUS              Status;
206   UINT32                  Data;
207 
208   EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_IAAD);
209 
210   Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_IAA, TRUE, Timeout);
211 
212   //
213   // ACK the IAA bit in USBSTS register. Make sure other
214   // interrupt bits are not ACKed. These bits are WC (Write Clean).
215   //
216   Data  = EhcReadOpReg (Ehc, EHC_USBSTS_OFFSET);
217   Data &= ~USBSTS_INTACK_MASK;
218   Data |= USBSTS_IAA;
219 
220   EhcWriteOpReg (Ehc, EHC_USBSTS_OFFSET, Data);
221 
222   return Status;
223 }
224 
225 /**
226   Clear all the interrutp status bits, these bits
227   are Write-Clean.
228 
229   @param  Ehc       The EHCI device.
230 
231 **/
232 VOID
EhcAckAllInterrupt(IN PEI_USB2_HC_DEV * Ehc)233 EhcAckAllInterrupt (
234   IN  PEI_USB2_HC_DEV         *Ehc
235   )
236 {
237   EhcWriteOpReg (Ehc, EHC_USBSTS_OFFSET, USBSTS_INTACK_MASK);
238 }
239 
240 /**
241   Enable the periodic schedule then wait EHC to
242   actually enable it.
243 
244   @param  Ehc       The EHCI device.
245   @param  Timeout   The time to wait before abort (in millisecond, ms).
246 
247   @retval EFI_TIMEOUT       Time out happened while enabling periodic schedule.
248   @retval EFI_SUCCESS       The periodical schedule is enabled.
249 
250 **/
251 EFI_STATUS
EhcEnablePeriodSchd(IN PEI_USB2_HC_DEV * Ehc,IN UINT32 Timeout)252 EhcEnablePeriodSchd (
253   IN PEI_USB2_HC_DEV      *Ehc,
254   IN UINT32               Timeout
255   )
256 {
257   EFI_STATUS              Status;
258 
259   EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_ENABLE_PERIOD);
260 
261   Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_PERIOD_ENABLED, TRUE, Timeout);
262   return Status;
263 }
264 
265 /**
266   Enable asynchrounous schedule.
267 
268   @param  Ehc       The EHCI device.
269   @param  Timeout   Time to wait before abort.
270 
271   @retval EFI_SUCCESS       The EHCI asynchronous schedule is enabled.
272   @retval Others            Failed to enable the asynchronous scheudle.
273 
274 **/
275 EFI_STATUS
EhcEnableAsyncSchd(IN PEI_USB2_HC_DEV * Ehc,IN UINT32 Timeout)276 EhcEnableAsyncSchd (
277   IN PEI_USB2_HC_DEV      *Ehc,
278   IN UINT32               Timeout
279   )
280 {
281   EFI_STATUS              Status;
282 
283   EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_ENABLE_ASYNC);
284 
285   Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_ASYNC_ENABLED, TRUE, Timeout);
286   return Status;
287 }
288 
289 /**
290   Check whether Ehc is halted.
291 
292   @param  Ehc       The EHCI device.
293 
294   @retval TRUE      The controller is halted.
295   @retval FALSE     The controller isn't halted.
296 
297 **/
298 BOOLEAN
EhcIsHalt(IN PEI_USB2_HC_DEV * Ehc)299 EhcIsHalt (
300   IN PEI_USB2_HC_DEV      *Ehc
301   )
302 {
303   return EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT);
304 }
305 
306 /**
307   Check whether system error occurred.
308 
309   @param  Ehc       The EHCI device.
310 
311   @retval TRUE      System error happened.
312   @retval FALSE     No system error.
313 
314 **/
315 BOOLEAN
EhcIsSysError(IN PEI_USB2_HC_DEV * Ehc)316 EhcIsSysError (
317   IN PEI_USB2_HC_DEV      *Ehc
318   )
319 {
320   return EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_SYS_ERROR);
321 }
322 
323 /**
324   Reset the host controller.
325 
326   @param  Ehc             The EHCI device.
327   @param  Timeout         Time to wait before abort (in millisecond, ms).
328 
329   @retval EFI_TIMEOUT     The transfer failed due to time out.
330   @retval Others          Failed to reset the host.
331 
332 **/
333 EFI_STATUS
EhcResetHC(IN PEI_USB2_HC_DEV * Ehc,IN UINT32 Timeout)334 EhcResetHC (
335   IN PEI_USB2_HC_DEV      *Ehc,
336   IN UINT32               Timeout
337   )
338 {
339   EFI_STATUS              Status;
340 
341   //
342   // Host can only be reset when it is halt. If not so, halt it
343   //
344   if (!EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT)) {
345     Status = EhcHaltHC (Ehc, Timeout);
346 
347     if (EFI_ERROR (Status)) {
348       return Status;
349     }
350   }
351 
352   EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RESET);
353   Status = EhcWaitOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RESET, FALSE, Timeout);
354   return Status;
355 }
356 
357 /**
358   Halt the host controller.
359 
360   @param  Ehc             The EHCI device.
361   @param  Timeout         Time to wait before abort.
362 
363   @retval EFI_TIMEOUT     Failed to halt the controller before Timeout.
364   @retval EFI_SUCCESS     The EHCI is halt.
365 
366 **/
367 EFI_STATUS
EhcHaltHC(IN PEI_USB2_HC_DEV * Ehc,IN UINT32 Timeout)368 EhcHaltHC (
369   IN PEI_USB2_HC_DEV     *Ehc,
370   IN UINT32              Timeout
371   )
372 {
373   EFI_STATUS              Status;
374 
375   EhcClearOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RUN);
376   Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT, TRUE, Timeout);
377   return Status;
378 }
379 
380 /**
381   Set the EHCI to run.
382 
383   @param  Ehc             The EHCI device.
384   @param  Timeout         Time to wait before abort.
385 
386   @retval EFI_SUCCESS     The EHCI is running.
387   @retval Others          Failed to set the EHCI to run.
388 
389 **/
390 EFI_STATUS
EhcRunHC(IN PEI_USB2_HC_DEV * Ehc,IN UINT32 Timeout)391 EhcRunHC (
392   IN PEI_USB2_HC_DEV      *Ehc,
393   IN UINT32               Timeout
394   )
395 {
396   EFI_STATUS              Status;
397 
398   EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RUN);
399   Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT, FALSE, Timeout);
400   return Status;
401 }
402 
403 /**
404   Power On All EHCI Ports.
405 
406   @param  Ehc             The EHCI device.
407 
408 **/
409 VOID
EhcPowerOnAllPorts(IN PEI_USB2_HC_DEV * Ehc)410 EhcPowerOnAllPorts (
411   IN PEI_USB2_HC_DEV          *Ehc
412   )
413 {
414   UINT8 PortNumber;
415   UINT8 Index;
416 
417   PortNumber = (UINT8)(Ehc->HcStructParams & HCSP_NPORTS);
418   for (Index = 0; Index < PortNumber; Index++) {
419     EhcSetOpRegBit (Ehc, EHC_PORT_STAT_OFFSET + 4 * Index, PORTSC_POWER);
420   }
421 }
422 
423 /**
424   Initialize the HC hardware.
425   EHCI spec lists the five things to do to initialize the hardware.
426   1. Program CTRLDSSEGMENT.
427   2. Set USBINTR to enable interrupts.
428   3. Set periodic list base.
429   4. Set USBCMD, interrupt threshold, frame list size etc.
430   5. Write 1 to CONFIGFLAG to route all ports to EHCI.
431 
432   @param  Ehc             The EHCI device.
433 
434   @retval EFI_SUCCESS     The EHCI has come out of halt state.
435   @retval EFI_TIMEOUT     Time out happened.
436 
437 **/
438 EFI_STATUS
EhcInitHC(IN PEI_USB2_HC_DEV * Ehc)439 EhcInitHC (
440   IN PEI_USB2_HC_DEV      *Ehc
441   )
442 {
443   EFI_STATUS              Status;
444   EFI_PHYSICAL_ADDRESS        TempPtr;
445   UINTN               PageNumber;
446 
447   ASSERT (EhcIsHalt (Ehc));
448 
449   //
450   // Allocate the periodic frame and associated memeory
451   // management facilities if not already done.
452   //
453   if (Ehc->PeriodFrame != NULL) {
454     EhcFreeSched (Ehc);
455   }
456   PageNumber =  sizeof(PEI_URB)/PAGESIZE +1;
457   Status = PeiServicesAllocatePages (
458              EfiBootServicesCode,
459              PageNumber,
460              &TempPtr
461              );
462   Ehc->Urb = (PEI_URB *) ((UINTN) TempPtr);
463   if (Ehc->Urb  == NULL) {
464     return Status;
465   }
466 
467   EhcPowerOnAllPorts (Ehc);
468   MicroSecondDelay (EHC_ROOT_PORT_RECOVERY_STALL);
469 
470   Status = EhcInitSched (Ehc);
471 
472   if (EFI_ERROR (Status)) {
473     return Status;
474   }
475   //
476   // 1. Program the CTRLDSSEGMENT register with the high 32 bit addr
477   //
478   EhcWriteOpReg (Ehc, EHC_CTRLDSSEG_OFFSET, Ehc->High32bitAddr);
479 
480   //
481   // 2. Clear USBINTR to disable all the interrupt. UEFI works by polling
482   //
483   EhcWriteOpReg (Ehc, EHC_USBINTR_OFFSET, 0);
484 
485   //
486   // 3. Program periodic frame list, already done in EhcInitSched
487   // 4. Start the Host Controller
488   //
489   EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RUN);
490 
491   //
492   // 5. Set all ports routing to EHC
493   //
494   EhcSetOpRegBit (Ehc, EHC_CONFIG_FLAG_OFFSET, CONFIGFLAG_ROUTE_EHC);
495 
496   //
497   // Wait roothub port power stable
498   //
499   MicroSecondDelay (EHC_ROOT_PORT_RECOVERY_STALL);
500 
501   Status = EhcEnablePeriodSchd (Ehc, EHC_GENERIC_TIMEOUT);
502 
503   if (EFI_ERROR (Status)) {
504     return Status;
505   }
506 
507   Status = EhcEnableAsyncSchd (Ehc, EHC_GENERIC_TIMEOUT);
508 
509   if (EFI_ERROR (Status)) {
510     return Status;
511   }
512 
513   return EFI_SUCCESS;
514 }
515 
516 /**
517   Submits bulk transfer to a bulk endpoint of a USB device.
518 
519   @param  PeiServices           The pointer of EFI_PEI_SERVICES.
520   @param  This                  The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
521   @param  DeviceAddress         Target device address.
522   @param  EndPointAddress       Endpoint number and its direction in bit 7.
523   @param  DeviceSpeed           Device speed, Low speed device doesn't support
524                                 bulk transfer.
525   @param  MaximumPacketLength   Maximum packet size the endpoint is capable of
526                                 sending or receiving.
527   @param  Data                  Array of pointers to the buffers of data to transmit
528                                 from or receive into.
529   @param  DataLength            The lenght of the data buffer.
530   @param  DataToggle            On input, the initial data toggle for the transfer;
531                                 On output, it is updated to to next data toggle to use of
532                                 the subsequent bulk transfer.
533   @param  TimeOut               Indicates the maximum time, in millisecond, which the
534                                 transfer is allowed to complete.
535                                 If Timeout is 0, then the caller must wait for the function
536                                 to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
537   @param  Translator            A pointr to the transaction translator data.
538   @param  TransferResult        A pointer to the detailed result information of the
539                                 bulk transfer.
540 
541   @retval EFI_SUCCESS           The transfer was completed successfully.
542   @retval EFI_OUT_OF_RESOURCES  The transfer failed due to lack of resource.
543   @retval EFI_INVALID_PARAMETER Parameters are invalid.
544   @retval EFI_TIMEOUT           The transfer failed due to timeout.
545   @retval EFI_DEVICE_ERROR      The transfer failed due to host controller error.
546 
547 **/
548 EFI_STATUS
549 EFIAPI
EhcBulkTransfer(IN EFI_PEI_SERVICES ** PeiServices,IN PEI_USB2_HOST_CONTROLLER_PPI * This,IN UINT8 DeviceAddress,IN UINT8 EndPointAddress,IN UINT8 DeviceSpeed,IN UINTN MaximumPacketLength,IN OUT VOID * Data[EFI_USB_MAX_BULK_BUFFER_NUM],IN OUT UINTN * DataLength,IN OUT UINT8 * DataToggle,IN UINTN TimeOut,IN EFI_USB2_HC_TRANSACTION_TRANSLATOR * Translator,OUT UINT32 * TransferResult)550 EhcBulkTransfer (
551   IN EFI_PEI_SERVICES                     **PeiServices,
552   IN PEI_USB2_HOST_CONTROLLER_PPI         *This,
553   IN  UINT8                               DeviceAddress,
554   IN  UINT8                               EndPointAddress,
555   IN  UINT8                               DeviceSpeed,
556   IN  UINTN                               MaximumPacketLength,
557   IN  OUT VOID                            *Data[EFI_USB_MAX_BULK_BUFFER_NUM],
558   IN  OUT UINTN                           *DataLength,
559   IN  OUT UINT8                           *DataToggle,
560   IN  UINTN                               TimeOut,
561   IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,
562   OUT UINT32                              *TransferResult
563   )
564 {
565   PEI_USB2_HC_DEV         *Ehc;
566   PEI_URB                 *Urb;
567   EFI_STATUS              Status;
568 
569   //
570   // Validate the parameters
571   //
572   if ((DataLength == NULL) || (*DataLength == 0) ||
573       (Data == NULL) || (Data[0] == NULL) || (TransferResult == NULL)) {
574     return EFI_INVALID_PARAMETER;
575   }
576 
577   if ((*DataToggle != 0) && (*DataToggle != 1)) {
578     return EFI_INVALID_PARAMETER;
579   }
580 
581   if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||
582       ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||
583       ((EFI_USB_SPEED_HIGH == DeviceSpeed) && (MaximumPacketLength > 512))) {
584     return EFI_INVALID_PARAMETER;
585   }
586 
587   Ehc =PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS(This);
588   *TransferResult = EFI_USB_ERR_SYSTEM;
589   Status          = EFI_DEVICE_ERROR;
590 
591   if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {
592     EhcAckAllInterrupt (Ehc);
593     goto ON_EXIT;
594   }
595 
596   EhcAckAllInterrupt (Ehc);
597 
598   //
599   // Create a new URB, insert it into the asynchronous
600   // schedule list, then poll the execution status.
601   //
602   Urb = EhcCreateUrb (
603           Ehc,
604           DeviceAddress,
605           EndPointAddress,
606           DeviceSpeed,
607           *DataToggle,
608           MaximumPacketLength,
609           Translator,
610           EHC_BULK_TRANSFER,
611           NULL,
612           Data[0],
613           *DataLength,
614           NULL,
615           NULL,
616           1
617           );
618 
619   if (Urb == NULL) {
620     Status = EFI_OUT_OF_RESOURCES;
621     goto ON_EXIT;
622   }
623 
624   EhcLinkQhToAsync (Ehc, Urb->Qh);
625   Status = EhcExecTransfer (Ehc, Urb, TimeOut);
626   EhcUnlinkQhFromAsync (Ehc, Urb->Qh);
627 
628   *TransferResult = Urb->Result;
629   *DataLength     = Urb->Completed;
630   *DataToggle     = Urb->DataToggle;
631 
632   if (*TransferResult == EFI_USB_NOERROR) {
633     Status = EFI_SUCCESS;
634   }
635 
636   EhcAckAllInterrupt (Ehc);
637   EhcFreeUrb (Ehc, Urb);
638 
639 ON_EXIT:
640   return Status;
641 }
642 
643 /**
644   Retrieves the number of root hub ports.
645 
646   @param[in]  PeiServices   The pointer to the PEI Services Table.
647   @param[in]  This          The pointer to this instance of the
648                             PEI_USB2_HOST_CONTROLLER_PPI.
649   @param[out] PortNumber    The pointer to the number of the root hub ports.
650 
651   @retval EFI_SUCCESS           The port number was retrieved successfully.
652   @retval EFI_INVALID_PARAMETER PortNumber is NULL.
653 
654 **/
655 EFI_STATUS
656 EFIAPI
EhcGetRootHubPortNumber(IN EFI_PEI_SERVICES ** PeiServices,IN PEI_USB2_HOST_CONTROLLER_PPI * This,OUT UINT8 * PortNumber)657 EhcGetRootHubPortNumber (
658   IN EFI_PEI_SERVICES                       **PeiServices,
659   IN PEI_USB2_HOST_CONTROLLER_PPI           *This,
660   OUT UINT8                                 *PortNumber
661   )
662 {
663 
664   PEI_USB2_HC_DEV             *EhcDev;
665   EhcDev = PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS (This);
666 
667   if (PortNumber == NULL) {
668     return EFI_INVALID_PARAMETER;
669   }
670 
671   *PortNumber = (UINT8)(EhcDev->HcStructParams & HCSP_NPORTS);
672   return EFI_SUCCESS;
673 
674 }
675 
676 /**
677   Clears a feature for the specified root hub port.
678 
679   @param  PeiServices           The pointer of EFI_PEI_SERVICES.
680   @param  This                  The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
681   @param  PortNumber            Specifies the root hub port whose feature
682                                 is requested to be cleared.
683   @param  PortFeature           Indicates the feature selector associated with the
684                                 feature clear request.
685 
686   @retval EFI_SUCCESS            The feature specified by PortFeature was cleared
687                                  for the USB root hub port specified by PortNumber.
688   @retval EFI_INVALID_PARAMETER  PortNumber is invalid or PortFeature is invalid.
689 
690 **/
691 EFI_STATUS
692 EFIAPI
EhcClearRootHubPortFeature(IN EFI_PEI_SERVICES ** PeiServices,IN PEI_USB2_HOST_CONTROLLER_PPI * This,IN UINT8 PortNumber,IN EFI_USB_PORT_FEATURE PortFeature)693 EhcClearRootHubPortFeature (
694   IN EFI_PEI_SERVICES                       **PeiServices,
695   IN PEI_USB2_HOST_CONTROLLER_PPI           *This,
696   IN  UINT8                 PortNumber,
697   IN  EFI_USB_PORT_FEATURE  PortFeature
698   )
699 {
700   PEI_USB2_HC_DEV         *Ehc;
701   UINT32                  Offset;
702   UINT32                  State;
703   UINT32                  TotalPort;
704   EFI_STATUS              Status;
705 
706   Ehc       = PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS (This);
707   Status    = EFI_SUCCESS;
708 
709   TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);
710 
711   if (PortNumber >= TotalPort) {
712     Status = EFI_INVALID_PARAMETER;
713     goto ON_EXIT;
714   }
715 
716   Offset  = EHC_PORT_STAT_OFFSET + (4 * PortNumber);
717   State   = EhcReadOpReg (Ehc, Offset);
718   State &= ~PORTSC_CHANGE_MASK;
719 
720   switch (PortFeature) {
721   case EfiUsbPortEnable:
722     //
723     // Clear PORT_ENABLE feature means disable port.
724     //
725     State &= ~PORTSC_ENABLED;
726     EhcWriteOpReg (Ehc, Offset, State);
727     break;
728 
729   case EfiUsbPortSuspend:
730     //
731     // A write of zero to this bit is ignored by the host
732     // controller. The host controller will unconditionally
733     // set this bit to a zero when:
734     //   1. software sets the Forct Port Resume bit to a zero from a one.
735     //   2. software sets the Port Reset bit to a one frome a zero.
736     //
737     State &= ~PORSTSC_RESUME;
738     EhcWriteOpReg (Ehc, Offset, State);
739     break;
740 
741   case EfiUsbPortReset:
742     //
743     // Clear PORT_RESET means clear the reset signal.
744     //
745     State &= ~PORTSC_RESET;
746     EhcWriteOpReg (Ehc, Offset, State);
747     break;
748 
749   case EfiUsbPortOwner:
750     //
751     // Clear port owner means this port owned by EHC
752     //
753     State &= ~PORTSC_OWNER;
754     EhcWriteOpReg (Ehc, Offset, State);
755     break;
756 
757   case EfiUsbPortConnectChange:
758     //
759     // Clear connect status change
760     //
761     State |= PORTSC_CONN_CHANGE;
762     EhcWriteOpReg (Ehc, Offset, State);
763     break;
764 
765   case EfiUsbPortEnableChange:
766     //
767     // Clear enable status change
768     //
769     State |= PORTSC_ENABLE_CHANGE;
770     EhcWriteOpReg (Ehc, Offset, State);
771     break;
772 
773   case EfiUsbPortOverCurrentChange:
774     //
775     // Clear PortOverCurrent change
776     //
777     State |= PORTSC_OVERCUR_CHANGE;
778     EhcWriteOpReg (Ehc, Offset, State);
779     break;
780 
781   case EfiUsbPortPower:
782   case EfiUsbPortSuspendChange:
783   case EfiUsbPortResetChange:
784     //
785     // Not supported or not related operation
786     //
787     break;
788 
789   default:
790     Status = EFI_INVALID_PARAMETER;
791     break;
792   }
793 
794 ON_EXIT:
795   return Status;
796 }
797 
798 /**
799   Sets a feature for the specified root hub port.
800 
801   @param  PeiServices           The pointer of EFI_PEI_SERVICES
802   @param  This                  The pointer of PEI_USB2_HOST_CONTROLLER_PPI
803   @param  PortNumber            Root hub port to set.
804   @param  PortFeature           Feature to set.
805 
806   @retval EFI_SUCCESS            The feature specified by PortFeature was set.
807   @retval EFI_INVALID_PARAMETER  PortNumber is invalid or PortFeature is invalid.
808   @retval EFI_TIMEOUT            The time out occurred.
809 
810 **/
811 EFI_STATUS
812 EFIAPI
EhcSetRootHubPortFeature(IN EFI_PEI_SERVICES ** PeiServices,IN PEI_USB2_HOST_CONTROLLER_PPI * This,IN UINT8 PortNumber,IN EFI_USB_PORT_FEATURE PortFeature)813 EhcSetRootHubPortFeature (
814   IN EFI_PEI_SERVICES                       **PeiServices,
815   IN PEI_USB2_HOST_CONTROLLER_PPI           *This,
816   IN UINT8                                  PortNumber,
817   IN EFI_USB_PORT_FEATURE                   PortFeature
818   )
819 {
820   PEI_USB2_HC_DEV         *Ehc;
821   UINT32                  Offset;
822   UINT32                  State;
823   UINT32                  TotalPort;
824   EFI_STATUS              Status;
825 
826   Ehc       = PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS (This);
827   Status    = EFI_SUCCESS;
828 
829   TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);
830 
831   if (PortNumber >= TotalPort) {
832     Status = EFI_INVALID_PARAMETER;
833     goto ON_EXIT;
834   }
835 
836   Offset  = (UINT32) (EHC_PORT_STAT_OFFSET + (4 * PortNumber));
837   State   = EhcReadOpReg (Ehc, Offset);
838 
839   //
840   // Mask off the port status change bits, these bits are
841   // write clean bit
842   //
843   State &= ~PORTSC_CHANGE_MASK;
844 
845   switch (PortFeature) {
846   case EfiUsbPortEnable:
847     //
848     // Sofeware can't set this bit, Port can only be enable by
849     // EHCI as a part of the reset and enable
850     //
851     State |= PORTSC_ENABLED;
852     EhcWriteOpReg (Ehc, Offset, State);
853     break;
854 
855   case EfiUsbPortSuspend:
856     State |= PORTSC_SUSPEND;
857     EhcWriteOpReg (Ehc, Offset, State);
858     break;
859 
860   case EfiUsbPortReset:
861     //
862     // Make sure Host Controller not halt before reset it
863     //
864     if (EhcIsHalt (Ehc)) {
865       Status = EhcRunHC (Ehc, EHC_GENERIC_TIMEOUT);
866 
867       if (EFI_ERROR (Status)) {
868         break;
869       }
870     }
871 
872     //
873     // Set one to PortReset bit must also set zero to PortEnable bit
874     //
875     State |= PORTSC_RESET;
876     State &= ~PORTSC_ENABLED;
877     EhcWriteOpReg (Ehc, Offset, State);
878     break;
879 
880   case EfiUsbPortPower:
881     //
882     // Not supported, ignore the operation
883     //
884     Status = EFI_SUCCESS;
885     break;
886 
887   case EfiUsbPortOwner:
888     State |= PORTSC_OWNER;
889     EhcWriteOpReg (Ehc, Offset, State);
890     break;
891 
892   default:
893     Status = EFI_INVALID_PARAMETER;
894   }
895 
896 ON_EXIT:
897   return Status;
898 }
899 
900 /**
901   Retrieves the current status of a USB root hub port.
902 
903   @param  PeiServices            The pointer of EFI_PEI_SERVICES.
904   @param  This                   The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
905   @param  PortNumber             The root hub port to retrieve the state from.
906   @param  PortStatus             Variable to receive the port state.
907 
908   @retval EFI_SUCCESS            The status of the USB root hub port specified.
909                                  by PortNumber was returned in PortStatus.
910   @retval EFI_INVALID_PARAMETER  PortNumber is invalid.
911 
912 **/
913 EFI_STATUS
914 EFIAPI
EhcGetRootHubPortStatus(IN EFI_PEI_SERVICES ** PeiServices,IN PEI_USB2_HOST_CONTROLLER_PPI * This,IN UINT8 PortNumber,OUT EFI_USB_PORT_STATUS * PortStatus)915 EhcGetRootHubPortStatus (
916   IN EFI_PEI_SERVICES                       **PeiServices,
917   IN PEI_USB2_HOST_CONTROLLER_PPI           *This,
918   IN  UINT8                                 PortNumber,
919   OUT EFI_USB_PORT_STATUS                   *PortStatus
920   )
921 {
922   PEI_USB2_HC_DEV         *Ehc;
923   UINT32                  Offset;
924   UINT32                  State;
925   UINT32                  TotalPort;
926   UINTN                   Index;
927   UINTN                   MapSize;
928   EFI_STATUS              Status;
929 
930   if (PortStatus == NULL) {
931     return EFI_INVALID_PARAMETER;
932   }
933 
934   Ehc       =  PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS(This);
935   Status    = EFI_SUCCESS;
936 
937   TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);
938 
939   if (PortNumber >= TotalPort) {
940     Status = EFI_INVALID_PARAMETER;
941     goto ON_EXIT;
942   }
943 
944   Offset                        = (UINT32) (EHC_PORT_STAT_OFFSET + (4 * PortNumber));
945   PortStatus->PortStatus        = 0;
946   PortStatus->PortChangeStatus  = 0;
947 
948   State                         = EhcReadOpReg (Ehc, Offset);
949 
950   //
951   // Identify device speed. If in K state, it is low speed.
952   // If the port is enabled after reset, the device is of
953   // high speed. The USB bus driver should retrieve the actual
954   // port speed after reset.
955   //
956   if (EHC_BIT_IS_SET (State, PORTSC_LINESTATE_K)) {
957     PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;
958 
959   } else if (EHC_BIT_IS_SET (State, PORTSC_ENABLED)) {
960     PortStatus->PortStatus |= USB_PORT_STAT_HIGH_SPEED;
961   }
962 
963   //
964   // Convert the EHCI port/port change state to UEFI status
965   //
966   MapSize = sizeof (mUsbPortStateMap) / sizeof (USB_PORT_STATE_MAP);
967 
968   for (Index = 0; Index < MapSize; Index++) {
969     if (EHC_BIT_IS_SET (State, mUsbPortStateMap[Index].HwState)) {
970       PortStatus->PortStatus = (UINT16) (PortStatus->PortStatus | mUsbPortStateMap[Index].UefiState);
971     }
972   }
973 
974   MapSize = sizeof (mUsbPortChangeMap) / sizeof (USB_PORT_STATE_MAP);
975 
976   for (Index = 0; Index < MapSize; Index++) {
977     if (EHC_BIT_IS_SET (State, mUsbPortChangeMap[Index].HwState)) {
978       PortStatus->PortChangeStatus = (UINT16) (PortStatus->PortChangeStatus | mUsbPortChangeMap[Index].UefiState);
979     }
980   }
981 
982 ON_EXIT:
983   return Status;
984 }
985 
986 /**
987   Submits control transfer to a target USB device.
988 
989   @param  PeiServices            The pointer of EFI_PEI_SERVICES.
990   @param  This                   The pointer of PEI_USB2_HOST_CONTROLLER_PPI.
991   @param  DeviceAddress          The target device address.
992   @param  DeviceSpeed            Target device speed.
993   @param  MaximumPacketLength    Maximum packet size the default control transfer
994                                  endpoint is capable of sending or receiving.
995   @param  Request                USB device request to send.
996   @param  TransferDirection      Specifies the data direction for the data stage.
997   @param  Data                   Data buffer to be transmitted or received from USB device.
998   @param  DataLength             The size (in bytes) of the data buffer.
999   @param  TimeOut                Indicates the maximum timeout, in millisecond.
1000                                  If Timeout is 0, then the caller must wait for the function
1001                                  to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
1002   @param  Translator             Transaction translator to be used by this device.
1003   @param  TransferResult         Return the result of this control transfer.
1004 
1005   @retval EFI_SUCCESS            Transfer was completed successfully.
1006   @retval EFI_OUT_OF_RESOURCES   The transfer failed due to lack of resources.
1007   @retval EFI_INVALID_PARAMETER  Some parameters are invalid.
1008   @retval EFI_TIMEOUT            Transfer failed due to timeout.
1009   @retval EFI_DEVICE_ERROR       Transfer failed due to host controller or device error.
1010 
1011 **/
1012 EFI_STATUS
1013 EFIAPI
EhcControlTransfer(IN EFI_PEI_SERVICES ** PeiServices,IN PEI_USB2_HOST_CONTROLLER_PPI * This,IN UINT8 DeviceAddress,IN UINT8 DeviceSpeed,IN UINTN MaximumPacketLength,IN EFI_USB_DEVICE_REQUEST * Request,IN EFI_USB_DATA_DIRECTION TransferDirection,IN OUT VOID * Data,IN OUT UINTN * DataLength,IN UINTN TimeOut,IN EFI_USB2_HC_TRANSACTION_TRANSLATOR * Translator,OUT UINT32 * TransferResult)1014 EhcControlTransfer (
1015   IN  EFI_PEI_SERVICES                    **PeiServices,
1016   IN  PEI_USB2_HOST_CONTROLLER_PPI        *This,
1017   IN  UINT8                               DeviceAddress,
1018   IN  UINT8                               DeviceSpeed,
1019   IN  UINTN                               MaximumPacketLength,
1020   IN  EFI_USB_DEVICE_REQUEST              *Request,
1021   IN  EFI_USB_DATA_DIRECTION              TransferDirection,
1022   IN  OUT VOID                            *Data,
1023   IN  OUT UINTN                           *DataLength,
1024   IN  UINTN                               TimeOut,
1025   IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,
1026   OUT UINT32                              *TransferResult
1027   )
1028 {
1029   PEI_USB2_HC_DEV         *Ehc;
1030   PEI_URB                 *Urb;
1031   UINT8                   Endpoint;
1032   EFI_STATUS              Status;
1033 
1034   //
1035   // Validate parameters
1036   //
1037   if ((Request == NULL) || (TransferResult == NULL)) {
1038     return EFI_INVALID_PARAMETER;
1039   }
1040 
1041   if ((TransferDirection != EfiUsbDataIn) &&
1042       (TransferDirection != EfiUsbDataOut) &&
1043       (TransferDirection != EfiUsbNoData)) {
1044     return EFI_INVALID_PARAMETER;
1045   }
1046 
1047   if ((TransferDirection == EfiUsbNoData) &&
1048       ((Data != NULL) || (*DataLength != 0))) {
1049     return EFI_INVALID_PARAMETER;
1050   }
1051 
1052   if ((TransferDirection != EfiUsbNoData) &&
1053      ((Data == NULL) || (*DataLength == 0))) {
1054     return EFI_INVALID_PARAMETER;
1055   }
1056 
1057   if ((MaximumPacketLength != 8)  && (MaximumPacketLength != 16) &&
1058       (MaximumPacketLength != 32) && (MaximumPacketLength != 64)) {
1059     return EFI_INVALID_PARAMETER;
1060   }
1061 
1062 
1063   if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||
1064       ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||
1065       ((EFI_USB_SPEED_HIGH == DeviceSpeed) && (MaximumPacketLength > 512))) {
1066     return EFI_INVALID_PARAMETER;
1067   }
1068 
1069   Ehc             = PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS (This);
1070 
1071   Status          = EFI_DEVICE_ERROR;
1072   *TransferResult = EFI_USB_ERR_SYSTEM;
1073 
1074   if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {
1075     EhcAckAllInterrupt (Ehc);
1076     goto ON_EXIT;
1077   }
1078 
1079   EhcAckAllInterrupt (Ehc);
1080 
1081   //
1082   // Create a new URB, insert it into the asynchronous
1083   // schedule list, then poll the execution status.
1084   //
1085   //
1086   // Encode the direction in address, although default control
1087   // endpoint is bidirectional. EhcCreateUrb expects this
1088   // combination of Ep addr and its direction.
1089   //
1090   Endpoint = (UINT8) (0 | ((TransferDirection == EfiUsbDataIn) ? 0x80 : 0));
1091   Urb = EhcCreateUrb (
1092           Ehc,
1093           DeviceAddress,
1094           Endpoint,
1095           DeviceSpeed,
1096           0,
1097           MaximumPacketLength,
1098           Translator,
1099           EHC_CTRL_TRANSFER,
1100           Request,
1101           Data,
1102           *DataLength,
1103           NULL,
1104           NULL,
1105           1
1106           );
1107 
1108   if (Urb == NULL) {
1109     Status = EFI_OUT_OF_RESOURCES;
1110     goto ON_EXIT;
1111   }
1112 
1113   EhcLinkQhToAsync (Ehc, Urb->Qh);
1114   Status = EhcExecTransfer (Ehc, Urb, TimeOut);
1115   EhcUnlinkQhFromAsync (Ehc, Urb->Qh);
1116 
1117   //
1118   // Get the status from URB. The result is updated in EhcCheckUrbResult
1119   // which is called by EhcExecTransfer
1120   //
1121   *TransferResult = Urb->Result;
1122   *DataLength     = Urb->Completed;
1123 
1124   if (*TransferResult == EFI_USB_NOERROR) {
1125     Status = EFI_SUCCESS;
1126   }
1127 
1128   EhcAckAllInterrupt (Ehc);
1129   EhcFreeUrb (Ehc, Urb);
1130 
1131 ON_EXIT:
1132   return Status;
1133 }
1134 
1135 /**
1136   @param  FileHandle  Handle of the file being invoked.
1137   @param  PeiServices Describes the list of possible PEI Services.
1138 
1139   @retval EFI_SUCCESS            PPI successfully installed.
1140 
1141 **/
1142 EFI_STATUS
1143 EFIAPI
EhcPeimEntry(IN EFI_PEI_FILE_HANDLE FileHandle,IN CONST EFI_PEI_SERVICES ** PeiServices)1144 EhcPeimEntry (
1145   IN EFI_PEI_FILE_HANDLE     FileHandle,
1146   IN CONST EFI_PEI_SERVICES  **PeiServices
1147   )
1148 {
1149   PEI_USB_CONTROLLER_PPI      *ChipSetUsbControllerPpi;
1150   EFI_STATUS                  Status;
1151   UINT8                       Index;
1152   UINTN                       ControllerType;
1153   UINTN                       BaseAddress;
1154   UINTN                       MemPages;
1155   PEI_USB2_HC_DEV             *EhcDev;
1156   EFI_PHYSICAL_ADDRESS        TempPtr;
1157 
1158   //
1159   // Shadow this PEIM to run from memory
1160   //
1161   if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
1162     return EFI_SUCCESS;
1163   }
1164 
1165   Status = PeiServicesLocatePpi (
1166              &gPeiUsbControllerPpiGuid,
1167              0,
1168              NULL,
1169              (VOID **) &ChipSetUsbControllerPpi
1170              );
1171   if (EFI_ERROR (Status)) {
1172     return EFI_UNSUPPORTED;
1173   }
1174 
1175   Index = 0;
1176   while (TRUE) {
1177     Status = ChipSetUsbControllerPpi->GetUsbController (
1178                                         (EFI_PEI_SERVICES **) PeiServices,
1179                                         ChipSetUsbControllerPpi,
1180                                         Index,
1181                                         &ControllerType,
1182                                         &BaseAddress
1183                                         );
1184     //
1185     // When status is error, meant no controller is found
1186     //
1187     if (EFI_ERROR (Status)) {
1188       break;
1189     }
1190 
1191     //
1192     // This PEIM is for UHC type controller.
1193     //
1194     if (ControllerType != PEI_EHCI_CONTROLLER) {
1195       Index++;
1196       continue;
1197     }
1198 
1199     MemPages = sizeof (PEI_USB2_HC_DEV) / PAGESIZE + 1;
1200     Status = PeiServicesAllocatePages (
1201                EfiBootServicesCode,
1202                MemPages,
1203                &TempPtr
1204                );
1205     if (EFI_ERROR (Status)) {
1206       return EFI_OUT_OF_RESOURCES;
1207     }
1208 
1209     ZeroMem((VOID *)(UINTN)TempPtr, MemPages*PAGESIZE);
1210     EhcDev = (PEI_USB2_HC_DEV *) ((UINTN) TempPtr);
1211 
1212     EhcDev->Signature = USB2_HC_DEV_SIGNATURE;
1213 
1214     EhcDev->UsbHostControllerBaseAddress = (UINT32) BaseAddress;
1215 
1216 
1217     EhcDev->HcStructParams = EhcReadCapRegister (EhcDev, EHC_HCSPARAMS_OFFSET);
1218     EhcDev->HcCapParams    = EhcReadCapRegister (EhcDev, EHC_HCCPARAMS_OFFSET);
1219     EhcDev->CapLen         = EhcReadCapRegister (EhcDev, EHC_CAPLENGTH_OFFSET) & 0x0FF;
1220     //
1221     // Initialize Uhc's hardware
1222     //
1223     Status = InitializeUsbHC (EhcDev);
1224     if (EFI_ERROR (Status)) {
1225       return Status;
1226     }
1227 
1228     EhcDev->Usb2HostControllerPpi.ControlTransfer          = EhcControlTransfer;
1229     EhcDev->Usb2HostControllerPpi.BulkTransfer             = EhcBulkTransfer;
1230     EhcDev->Usb2HostControllerPpi.GetRootHubPortNumber     = EhcGetRootHubPortNumber;
1231     EhcDev->Usb2HostControllerPpi.GetRootHubPortStatus     = EhcGetRootHubPortStatus;
1232     EhcDev->Usb2HostControllerPpi.SetRootHubPortFeature    = EhcSetRootHubPortFeature;
1233     EhcDev->Usb2HostControllerPpi.ClearRootHubPortFeature  = EhcClearRootHubPortFeature;
1234 
1235     EhcDev->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
1236     EhcDev->PpiDescriptor.Guid = &gPeiUsb2HostControllerPpiGuid;
1237     EhcDev->PpiDescriptor.Ppi = &EhcDev->Usb2HostControllerPpi;
1238 
1239     Status = PeiServicesInstallPpi (&EhcDev->PpiDescriptor);
1240     if (EFI_ERROR (Status)) {
1241       Index++;
1242       continue;
1243     }
1244 
1245     Index++;
1246   }
1247 
1248   return EFI_SUCCESS;
1249 }
1250 
1251 /**
1252   @param  EhcDev                 EHCI Device.
1253 
1254   @retval EFI_SUCCESS            EHCI successfully initialized.
1255   @retval EFI_ABORTED            EHCI was failed to be initialized.
1256 
1257 **/
1258 EFI_STATUS
InitializeUsbHC(IN PEI_USB2_HC_DEV * EhcDev)1259 InitializeUsbHC (
1260   IN PEI_USB2_HC_DEV      *EhcDev
1261   )
1262 {
1263   EFI_STATUS  Status;
1264 
1265 
1266   EhcResetHC (EhcDev, EHC_RESET_TIMEOUT);
1267 
1268   Status = EhcInitHC (EhcDev);
1269 
1270   if (EFI_ERROR (Status)) {
1271     return EFI_ABORTED;
1272   }
1273 
1274   return EFI_SUCCESS;
1275 }
1276