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