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