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