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